C++ 将派生类对象传递给模板类的构造函数
大家好 我的问题如下:C++ 将派生类对象传递给模板类的构造函数,c++,C++,大家好 我的问题如下: template <typename MyClass> TemplateClass { typedef void (MyClass::*MethodPointer)(); MyClass* theClass; MethodPointer methodPointer; public: TemplateClass(MyClass* cl, MethodPointer func) : theClass(cl),
template <typename MyClass>
TemplateClass
{
typedef void (MyClass::*MethodPointer)();
MyClass* theClass;
MethodPointer methodPointer;
public:
TemplateClass(MyClass* cl, MethodPointer func) : theClass(cl), methodPointer(func){}
void Excute()
{
return (theClass->*methodPointer)();
}
};
DerivedClass* myDerivedObject = new DerivedClass();
TypedTemplateClass* myTemplateObject = new TypedTemplateClass(myDerivedObject, &DerivedClass::DoSomething);
BaseClass* baseObject = new BaseClass();
TypedTemplateClass* myTemplateObject2 = new TypedTemplateClass(baseObject, &BaseClass::DoSomething);
#include <functional>
namespace eventhandling
{
#ifndef __BASIC_EVENT_HANDLER__
#define __BASIC_EVENT_HANDLER__
////////////////////////////////////////////////////////////////////////////
// the root event handler class
////////////////////////////////////////////////////////////////////////////
template <typename empty = int, empty = 0>
class BaseEventHandler
{
public:
virtual void Excute() = 0;
};
///////////////////////////////////////////////////////////////////////////
// the basic derived event handler class; the class which will wrap the
// methods of other classes which want to respond to specific event(s)..
///////////////////////////////////////////////////////////////////////////
template <typename ResponderType>
class EventHandler : public BaseEventHandler < >
{
typedef void (ResponderType::*MethodPointer());
ResponderType* responder;
MethodPointer methodPointer;
public:
EventHandler(ResponderType* resp, MethodPointer func) : responder(resp), methodPointer(func)
{}
void Excute()
{
return methodPointer();
}
};
#endif
}
#include "BasicEventHandler.h"
#include <map>
namespace eventhandling
{
#ifndef __BASIC_EVENT__
#define __BASIC_EVENT__
////////////////////////////////////////////////////////////////////////////////////////////////
// the event class which will receive these event handlers, stores them in a map object,
// and call them squentially when invoked from within the event firing method...
////////////////////////////////////////////////////////////////////////////////////////////////
// the template takes no parameters, so I added an empty parameter, just because
//it cannot ignore the parameter list, otherwise it will be considered template specialization
template <typename empty = int, empty = 0>
class BasicEvent
{
//store the eventhandlers in a map so that I can track them from outside the class by id
typedef std::map<int, BaseEventHandler<empty>* > Responders;
Responders responders;
int respondersCount;
public:
BasicEvent() : respondersCount(0)
{}
// classical add method templatized so that it accepts any object
template <typename Responder>
int Add(Responder* sender, void (Responder::*memberFunc)())
{
responders[respondersCount] = (new EventHandler<Responder>(sender, memberFunc));
respondersCount++;
return respondersCount - 1;
}
// simple method to clean up the map memory after done with the eventhandlers
void Remove(int responderID)
{
Responders::iterator it = responders.find(responderID);
if (it == responders.end())
return;
delete it->second;
responders.erase(it);
}
// method which invokes all the eventhandlers alltogether without control from the outside
void Invoke()
{
Responders::iterator it = responders.begin();
for (; it != responders.end(); ++it)
{
it->second->Excute();
}
}
// method which invokes only the eventhandler whose id has been passed to it
void Invoke(int id)
{
Responders::iterator it = responders.find(id);
if (it != responders.end())
it->second->Excute();
}
// overloaded operator+= to replace the functionality of method Add()
template <typename Responder>
void operator+=(EventHandler<Responder>* eventhandler)
{
responders[respondersCount] = eventhandler;
respondersCount++;
}
// overloaded operator -= to replace the functionality of method Remove()
void operator-=(int id)
{
Responders::iterator it = responders.find(id);
if (it == responders.end())
return;
delete it->second;
responders.erase(it);
}
//simple method which gives the size of the map object
int Size()
{
return respondersCount;
}
};
#endif
}
我有一个模板类,它存储指向其他类的方法的指针(当然,模板类最初不知道要传递给它的类的类型)。
我让template类的构造函数获取一个指向传入类的指针和另一个参数,该参数是我要存储的传入类的方法的地址,如下所示:
template <typename MyClass>
TemplateClass
{
typedef void (MyClass::*MethodPointer)();
MyClass* theClass;
MethodPointer methodPointer;
public:
TemplateClass(MyClass* cl, MethodPointer func) : theClass(cl), methodPointer(func){}
void Excute()
{
return (theClass->*methodPointer)();
}
};
DerivedClass* myDerivedObject = new DerivedClass();
TypedTemplateClass* myTemplateObject = new TypedTemplateClass(myDerivedObject, &DerivedClass::DoSomething);
BaseClass* baseObject = new BaseClass();
TypedTemplateClass* myTemplateObject2 = new TypedTemplateClass(baseObject, &BaseClass::DoSomething);
#include <functional>
namespace eventhandling
{
#ifndef __BASIC_EVENT_HANDLER__
#define __BASIC_EVENT_HANDLER__
////////////////////////////////////////////////////////////////////////////
// the root event handler class
////////////////////////////////////////////////////////////////////////////
template <typename empty = int, empty = 0>
class BaseEventHandler
{
public:
virtual void Excute() = 0;
};
///////////////////////////////////////////////////////////////////////////
// the basic derived event handler class; the class which will wrap the
// methods of other classes which want to respond to specific event(s)..
///////////////////////////////////////////////////////////////////////////
template <typename ResponderType>
class EventHandler : public BaseEventHandler < >
{
typedef void (ResponderType::*MethodPointer());
ResponderType* responder;
MethodPointer methodPointer;
public:
EventHandler(ResponderType* resp, MethodPointer func) : responder(resp), methodPointer(func)
{}
void Excute()
{
return methodPointer();
}
};
#endif
}
#include "BasicEventHandler.h"
#include <map>
namespace eventhandling
{
#ifndef __BASIC_EVENT__
#define __BASIC_EVENT__
////////////////////////////////////////////////////////////////////////////////////////////////
// the event class which will receive these event handlers, stores them in a map object,
// and call them squentially when invoked from within the event firing method...
////////////////////////////////////////////////////////////////////////////////////////////////
// the template takes no parameters, so I added an empty parameter, just because
//it cannot ignore the parameter list, otherwise it will be considered template specialization
template <typename empty = int, empty = 0>
class BasicEvent
{
//store the eventhandlers in a map so that I can track them from outside the class by id
typedef std::map<int, BaseEventHandler<empty>* > Responders;
Responders responders;
int respondersCount;
public:
BasicEvent() : respondersCount(0)
{}
// classical add method templatized so that it accepts any object
template <typename Responder>
int Add(Responder* sender, void (Responder::*memberFunc)())
{
responders[respondersCount] = (new EventHandler<Responder>(sender, memberFunc));
respondersCount++;
return respondersCount - 1;
}
// simple method to clean up the map memory after done with the eventhandlers
void Remove(int responderID)
{
Responders::iterator it = responders.find(responderID);
if (it == responders.end())
return;
delete it->second;
responders.erase(it);
}
// method which invokes all the eventhandlers alltogether without control from the outside
void Invoke()
{
Responders::iterator it = responders.begin();
for (; it != responders.end(); ++it)
{
it->second->Excute();
}
}
// method which invokes only the eventhandler whose id has been passed to it
void Invoke(int id)
{
Responders::iterator it = responders.find(id);
if (it != responders.end())
it->second->Excute();
}
// overloaded operator+= to replace the functionality of method Add()
template <typename Responder>
void operator+=(EventHandler<Responder>* eventhandler)
{
responders[respondersCount] = eventhandler;
respondersCount++;
}
// overloaded operator -= to replace the functionality of method Remove()
void operator-=(int id)
{
Responders::iterator it = responders.find(id);
if (it == responders.end())
return;
delete it->second;
responders.erase(it);
}
//simple method which gives the size of the map object
int Size()
{
return respondersCount;
}
};
#endif
}
然后,我以基类为参数制作了模板类的typedef,如:
typedef TemplateClass<BaseClass> TypedTemplateClass;
但是如果我传递了基类本身的对象,那么一切都很好!具体如下:
template <typename MyClass>
TemplateClass
{
typedef void (MyClass::*MethodPointer)();
MyClass* theClass;
MethodPointer methodPointer;
public:
TemplateClass(MyClass* cl, MethodPointer func) : theClass(cl), methodPointer(func){}
void Excute()
{
return (theClass->*methodPointer)();
}
};
DerivedClass* myDerivedObject = new DerivedClass();
TypedTemplateClass* myTemplateObject = new TypedTemplateClass(myDerivedObject, &DerivedClass::DoSomething);
BaseClass* baseObject = new BaseClass();
TypedTemplateClass* myTemplateObject2 = new TypedTemplateClass(baseObject, &BaseClass::DoSomething);
#include <functional>
namespace eventhandling
{
#ifndef __BASIC_EVENT_HANDLER__
#define __BASIC_EVENT_HANDLER__
////////////////////////////////////////////////////////////////////////////
// the root event handler class
////////////////////////////////////////////////////////////////////////////
template <typename empty = int, empty = 0>
class BaseEventHandler
{
public:
virtual void Excute() = 0;
};
///////////////////////////////////////////////////////////////////////////
// the basic derived event handler class; the class which will wrap the
// methods of other classes which want to respond to specific event(s)..
///////////////////////////////////////////////////////////////////////////
template <typename ResponderType>
class EventHandler : public BaseEventHandler < >
{
typedef void (ResponderType::*MethodPointer());
ResponderType* responder;
MethodPointer methodPointer;
public:
EventHandler(ResponderType* resp, MethodPointer func) : responder(resp), methodPointer(func)
{}
void Excute()
{
return methodPointer();
}
};
#endif
}
#include "BasicEventHandler.h"
#include <map>
namespace eventhandling
{
#ifndef __BASIC_EVENT__
#define __BASIC_EVENT__
////////////////////////////////////////////////////////////////////////////////////////////////
// the event class which will receive these event handlers, stores them in a map object,
// and call them squentially when invoked from within the event firing method...
////////////////////////////////////////////////////////////////////////////////////////////////
// the template takes no parameters, so I added an empty parameter, just because
//it cannot ignore the parameter list, otherwise it will be considered template specialization
template <typename empty = int, empty = 0>
class BasicEvent
{
//store the eventhandlers in a map so that I can track them from outside the class by id
typedef std::map<int, BaseEventHandler<empty>* > Responders;
Responders responders;
int respondersCount;
public:
BasicEvent() : respondersCount(0)
{}
// classical add method templatized so that it accepts any object
template <typename Responder>
int Add(Responder* sender, void (Responder::*memberFunc)())
{
responders[respondersCount] = (new EventHandler<Responder>(sender, memberFunc));
respondersCount++;
return respondersCount - 1;
}
// simple method to clean up the map memory after done with the eventhandlers
void Remove(int responderID)
{
Responders::iterator it = responders.find(responderID);
if (it == responders.end())
return;
delete it->second;
responders.erase(it);
}
// method which invokes all the eventhandlers alltogether without control from the outside
void Invoke()
{
Responders::iterator it = responders.begin();
for (; it != responders.end(); ++it)
{
it->second->Excute();
}
}
// method which invokes only the eventhandler whose id has been passed to it
void Invoke(int id)
{
Responders::iterator it = responders.find(id);
if (it != responders.end())
it->second->Excute();
}
// overloaded operator+= to replace the functionality of method Add()
template <typename Responder>
void operator+=(EventHandler<Responder>* eventhandler)
{
responders[respondersCount] = eventhandler;
respondersCount++;
}
// overloaded operator -= to replace the functionality of method Remove()
void operator-=(int id)
{
Responders::iterator it = responders.find(id);
if (it == responders.end())
return;
delete it->second;
responders.erase(it);
}
//simple method which gives the size of the map object
int Size()
{
return respondersCount;
}
};
#endif
}
那么,有人能启发我克服这个问题吗?
我知道问题在于类型化模板类需要一个基类对象,但我需要传递派生类对象——因为我打算生成不同的派生类,并且能够以多态方式将它们的方法传递给模板类。
我还知道,我可以忽略TypedTemplateClass定义,只创建每个具有不同派生类类型的模板类对象。不过,上述建议是我的意向
我正在使用VisualStudioIDE
提前感谢您的关注和善意帮助。问题在于,您无法将指向方法的指针从派生类型的指向方法的指针转换为指向基类型的指向方法的指针,因为指向方法的指针与对象类型相反 考虑:
Base instance;
void (Base::*pmethod)();
pmethod = &Base::doSomething;
(instance.*pmethod)(); // OK
如果你被允许写作
pmethod = &Derived::doSomethingElse;
然后,您可以使用pmethod
在类型为Base
的实例上调用派生::doSomethingElse
在下,派生对象(引用)是基对象(引用),因为可以对基执行的任何操作都可以对派生对象执行,但指向派生方法的指针不是指向基方法的指针;事实上,情况正好相反(指向Base方法的指针是派生方法的指针),这就是为什么我们说指向方法的指针是反变的:
void (Derived::*pmethod)() = &Base::doSomething;
在您的情况下,最好的办法可能是编写一个模板构造函数,并使用类型擦除来隐藏派生方法指针的类型;在下面
template<typename T>
TemplateClass(T *instance, void (T::*pmethod)());
问题在于,无法将指向方法的指针从派生类型的指向方法的指针转换为指向基类型的指向方法的指针,因为指向方法的指针与对象类型相反
考虑:
Base instance;
void (Base::*pmethod)();
pmethod = &Base::doSomething;
(instance.*pmethod)(); // OK
如果你被允许写作
pmethod = &Derived::doSomethingElse;
然后,您可以使用pmethod
在类型为Base
的实例上调用派生::doSomethingElse
在下,派生对象(引用)是基对象(引用),因为可以对基执行的任何操作都可以对派生对象执行,但指向派生方法的指针不是指向基方法的指针;事实上,情况正好相反(指向Base方法的指针是派生方法的指针),这就是为什么我们说指向方法的指针是反变的:
void (Derived::*pmethod)() = &Base::doSomething;
在您的情况下,最好的办法可能是编写一个模板构造函数,并使用类型擦除来隐藏派生方法指针的类型;在下面
template<typename T>
TemplateClass(T *instance, void (T::*pmethod)());
这意味着什么:TemplateClass(MyClass*class,&MyClass::SomeMethod)代码>不是一个有效的C++代码。你为什么不坚持C++标准库?如果需要存储可调用的,请使用由lambda构造的std::function
。编译器和库将负责所有必要的转换…这意味着什么:TemplateClass(MyClass*class,&MyClass::SomeMethod)代码>不是一个有效的C++代码。你为什么不坚持C++标准库?如果需要存储可调用的,请使用由lambda构造的std::function
。编译器和库将负责所有必要的转换…… ,嗯,我所做的这个项目是一个尝试,用以建立一个机制来处理C++中类似的事件,或多或少是事件和事件的C方式。
因此,在网上和一些文本内部研究并找出合适的方法后,我编写了两个模板类:
一种是存储成员方法的指针,并将其称为“EventHandler”。
另一种是存储事件处理程序的映射,并在需要时调用它们;这是“事件”类。
然后我写了两个“普通”类:一个是事件触发类,另一个是响应类或侦听类。
Event和EventHandler类的初始版本如下所示:
template <typename MyClass>
TemplateClass
{
typedef void (MyClass::*MethodPointer)();
MyClass* theClass;
MethodPointer methodPointer;
public:
TemplateClass(MyClass* cl, MethodPointer func) : theClass(cl), methodPointer(func){}
void Excute()
{
return (theClass->*methodPointer)();
}
};
DerivedClass* myDerivedObject = new DerivedClass();
TypedTemplateClass* myTemplateObject = new TypedTemplateClass(myDerivedObject, &DerivedClass::DoSomething);
BaseClass* baseObject = new BaseClass();
TypedTemplateClass* myTemplateObject2 = new TypedTemplateClass(baseObject, &BaseClass::DoSomething);
#include <functional>
namespace eventhandling
{
#ifndef __BASIC_EVENT_HANDLER__
#define __BASIC_EVENT_HANDLER__
////////////////////////////////////////////////////////////////////////////
// the root event handler class
////////////////////////////////////////////////////////////////////////////
template <typename empty = int, empty = 0>
class BaseEventHandler
{
public:
virtual void Excute() = 0;
};
///////////////////////////////////////////////////////////////////////////
// the basic derived event handler class; the class which will wrap the
// methods of other classes which want to respond to specific event(s)..
///////////////////////////////////////////////////////////////////////////
template <typename ResponderType>
class EventHandler : public BaseEventHandler < >
{
typedef void (ResponderType::*MethodPointer());
ResponderType* responder;
MethodPointer methodPointer;
public:
EventHandler(ResponderType* resp, MethodPointer func) : responder(resp), methodPointer(func)
{}
void Excute()
{
return methodPointer();
}
};
#endif
}
#include "BasicEventHandler.h"
#include <map>
namespace eventhandling
{
#ifndef __BASIC_EVENT__
#define __BASIC_EVENT__
////////////////////////////////////////////////////////////////////////////////////////////////
// the event class which will receive these event handlers, stores them in a map object,
// and call them squentially when invoked from within the event firing method...
////////////////////////////////////////////////////////////////////////////////////////////////
// the template takes no parameters, so I added an empty parameter, just because
//it cannot ignore the parameter list, otherwise it will be considered template specialization
template <typename empty = int, empty = 0>
class BasicEvent
{
//store the eventhandlers in a map so that I can track them from outside the class by id
typedef std::map<int, BaseEventHandler<empty>* > Responders;
Responders responders;
int respondersCount;
public:
BasicEvent() : respondersCount(0)
{}
// classical add method templatized so that it accepts any object
template <typename Responder>
int Add(Responder* sender, void (Responder::*memberFunc)())
{
responders[respondersCount] = (new EventHandler<Responder>(sender, memberFunc));
respondersCount++;
return respondersCount - 1;
}
// simple method to clean up the map memory after done with the eventhandlers
void Remove(int responderID)
{
Responders::iterator it = responders.find(responderID);
if (it == responders.end())
return;
delete it->second;
responders.erase(it);
}
// method which invokes all the eventhandlers alltogether without control from the outside
void Invoke()
{
Responders::iterator it = responders.begin();
for (; it != responders.end(); ++it)
{
it->second->Excute();
}
}
// method which invokes only the eventhandler whose id has been passed to it
void Invoke(int id)
{
Responders::iterator it = responders.find(id);
if (it != responders.end())
it->second->Excute();
}
// overloaded operator+= to replace the functionality of method Add()
template <typename Responder>
void operator+=(EventHandler<Responder>* eventhandler)
{
responders[respondersCount] = eventhandler;
respondersCount++;
}
// overloaded operator -= to replace the functionality of method Remove()
void operator-=(int id)
{
Responders::iterator it = responders.find(id);
if (it == responders.end())
return;
delete it->second;
responders.erase(it);
}
//simple method which gives the size of the map object
int Size()
{
return respondersCount;
}
};
#endif
}
当然,稍后完整的代码示例将使其更加清晰!
我的问题来了,我想在哪里传递MyClass的派生类的对象。问题在于,如上所示的EventHandler模板不接受此类派生对象,因为它只需要基类的对象,而编译器抱怨它无法从派生类转换为基类。
这里是ecatmur的宝贵帮助,他向我展示了使EventHandler类的构造函数模板化的正确方法。
这样,当我使用MyClass作为基类来定义SomeEventHandler时,我就能够将任何对象及其方法传递给它的构造函数,只要该对象来自MyClass派生的类。这是我实现EventHandler多态特性的最终目标。
我想要这个特性,因为如果您检查C#中的EventHandler,您可以看到System::EventHandler是多态的,它从类中接受不同的对象,我猜这些类本质上是从类对象派生的。
所以,这里是一个完整的例子,基于ecatmur解决方案的修正EventHandler类,供大家回顾,我希望你们会发现它有一些好处。
最终,您可以从BaseEventHandler类派生,以便派生的EventHandler可以存储具有不同返回类型和不同参数的方法