C++ 如何在类派生层次结构的所有步骤上调用方法?
举个例子:C++ 如何在类派生层次结构的所有步骤上调用方法?,c++,casting,C++,Casting,举个例子: #包括 #包括 #包括 #包括 类_IEventHandler{};//仅针对抽象模板类型 I类事件{ 公众: 虚拟void visitEventHandler(_IEventHandler*handler)=0; }; #定义扩展(类型、父类型)\ 公众:\ 使用ParentClass=parentType\ void visitEventHandler(_IEventHandler*处理程序)重写{\ 静态_cast(处理程序)->on(*this)\ } \ 样板 类别:公共{
#包括
#包括
#包括
#包括
类_IEventHandler{};//仅针对抽象模板类型
I类事件{
公众:
虚拟void visitEventHandler(_IEventHandler*handler)=0;
};
#定义扩展(类型、父类型)\
公众:\
使用ParentClass=parentType\
void visitEventHandler(_IEventHandler*处理程序)重写{\
静态_cast(处理程序)->on(*this)\
} \
样板
类别:公共{
公众:
//(事件&e)上的虚拟无效=0;
无效日期(事件与e){
std::cout这是目前解决我的问题的方法:
#包括
#包括
#包括
#包括
类_IEventHandler{};//仅用于抽象模板类型
I类事件{
公众:
虚拟无效访问\u IEventHandler(std::type_index _index,\u IEventHandler*处理程序){}
虚拟std::type\u索引getParentTypeIndex(std::type\u索引){
返回类型ID(IEvent);
}
};
#定义扩展(类型、父类型)\
公众:\
使用Class=type\
使用ParentClass=parentType\
std::type_index getParentTypeIndex(std::type_index index){\
如果(索引==类型ID(类型))\
返回typeid(ParentClass)\
否则\
返回ParentClass::getParentTypeIndex(索引)\
} \
#定义层次结构_访问者(interfaceType、reelType、methodName)\
公众:\
无效访问##接口类型(std::type_index _index,接口类型*_instanceToVisit)重写{\
如果(_index==typeid(类))\
静态_cast(_instanceToVisit)->methodName(*this)\
否则\
父类::访问##接口类型(_索引,_实例选项)\
} \
样板
类别:公共{
公众:
//(事件&e)上的虚拟无效=0;
无效日期(事件与e){
std::cout这个答案的关键词是“简化”和“封装”
让我们从简化开始。问题代码中有几个元素除了使代码变得比需要的更复杂之外没有其他用途(可能会有一点性能优势,但现在担心还为时过早)为了更好地了解实际解决方案是什么,我认为将这些改进包括在内是有益的。另一方面,这些改进只与实际解决方案间接相关,因此我将不详细说明每项改进的理由
将\u IEventHandler
重命名为BaseEventHandler
,以符合命名要求
在BaseEventHandler
中使on()
成为一个虚拟函数,以便visitEventHandler()
不需要静态转换
将visitEventHandler()
设置为非虚拟函数,因为现在所有实现都相同。
- 将
~IEvent()
声明为虚拟,以便IEvent
仍具有虚拟函数
删除扩展
宏,因为(宏是邪恶的,它定义的东西不再使用)
转到封装,让我们从EventBus
的角度来看问题。此类负责触发处理程序以响应事件。它已推断出每个处理程序需要哪个事件,并按这些事件类型组织处理程序。由于总线使用了现在他们想让我也知道事件类型之间的继承性???我需要更多信息,或者你自己去处理它
因为封装鼓励较少的信息,而不是更多的信息,让我们考虑另一个选项:处理它自己!ER,让处理程序决定是否要处理一个事件。这简化了<代码>事件总线< /代码>,因为它不再需要关心事件类型。它的<代码> map < <代码>包含<代码>向量< /代码> s可以成为一个S。单
vector
,它的hook()
方法不再需要是模板,它的fire()
方法可以放弃一直难以实现的循环。折衷是事件处理程序现在需要检查事件类型。幸运的是,dynamic\u cast
使检查非常简单
#include <iostream>
#include <vector>
#include <map>
class IEvent;
/* ** Event handler ** */
class BaseEventHandler {
public:
virtual void on(IEvent &) = 0;
};
template<typename Event>
class IEventHandler : public BaseEventHandler {
public:
void on(IEvent & e) override {
// Only fire for events of the templated type.
if ( dynamic_cast<Event *>(&e) )
std::cout << "handle " << typeid(Event).name() << std::endl;
}
};
/* ** Event ** */
class IEvent {
public:
virtual ~IEvent() {} // To force run time type information (RTTI)
void visitEventHandler(BaseEventHandler* handler)
{
handler->on(*this);
}
};
class EventA : public IEvent {};
class EventB : public EventA {};
class EventC : public EventB {};
class EventD : public EventC {};
/* ** Event Bus ** */
class EventBus {
public:
void fire(IEvent *event) {
for (BaseEventHandler *handler : m_handlers)
event->visitEventHandler(handler);
}
void hook(BaseEventHandler *handler) {
m_handlers.push_back(handler);
}
protected:
std::vector<BaseEventHandler *> m_handlers{};
};
int main() {
EventBus eb{};
IEventHandler<EventD> ehd{};
IEventHandler<EventC> ehc{};
IEventHandler<EventA> eha{};
eb.hook(&ehd);
eb.hook(&ehc);
eb.hook(&eha);
EventD eD{};
EventB eB{};
std::cout << "Firing event D.\n";
eb.fire(&eD); // need to stdout handle EventD handle EventC handle EventA
std::cout << "\nFiring event B.\n";
eb.fire(&eB); // need to stdout handle EventA
return 0;
}
#包括
#包括
#包括
I类事件;
/***事件处理程序***/
类BaseEventHandler{
公众:
(IEvent&)上的虚拟无效=0;
};
样板
类IEventHandler:公共BaseEventHandler{
公众:
(IEvent&e)覆盖无效{
//仅对模板类型的事件激发。
if(动态施法(&e))
std::cout这个答案的关键词是“简化”和“委派”
让我们从简化开始。问题代码中有几个元素除了使代码变得比需要的更复杂之外没有其他用途(可能会有一点性能优势,但现在担心还为时过早)为了更好地了解实际解决方案是什么,我认为将这些改进包括在内是有益的。另一方面,这些改进只与实际解决方案间接相关,因此我将不详细说明每项改进的理由
将\u IEventHandler
重命名为BaseEventHandler
,以符合命名要求
麦
#include <iostream>
#include <typeindex>
#include <vector>
#include <map>
class IEvent;
/* ** Event handler ** */
class BaseEventHandler {
public:
virtual void on(IEvent &) = 0;
};
template<typename Event>
class IEventHandler : public BaseEventHandler {
public:
void on(IEvent &) override {
std::cout << "handle " << typeid(Event).name() << std::endl;
}
};
using HandlerMap = std::map<std::type_index, std::vector<BaseEventHandler *>>;
/* ** Event ** */
class IEvent {
public:
// This is not an actual event type, so there are no handlers to visit.
virtual void visitEventHandlers(HandlerMap &) = 0;
};
// Need a definition for derived classes to call:
void IEvent::visitEventHandlers(HandlerMap &) {}
template<class Base>
class EventFrom : public Base {
public:
void visitEventHandlers(HandlerMap & handlers) override
{
// Visit the handlers for this specific event type.
for (BaseEventHandler *handler : handlers[typeid(EventFrom)])
handler->on(*this);
// Visit the handlers for the parent event type.
Base::visitEventHandlers(handlers);
}
};
using EventA = EventFrom<IEvent>;
using EventB = EventFrom<EventA>;
using EventC = EventFrom<EventB>;
using EventD = EventFrom<EventC>;
/* ** Event Bus ** */
class EventBus {
public:
void fire(IEvent *event) {
event->visitEventHandlers(m_handlers);
}
template<typename T>
void hook(IEventHandler<T> *handler) {
m_handlers[typeid(T)].push_back(handler);
}
protected:
HandlerMap m_handlers{};
};
int main() {
EventBus eb{};
IEventHandler<EventD> ehd{};
IEventHandler<EventC> ehc{};
IEventHandler<EventA> eha{};
eb.hook(&ehd);
eb.hook(&ehc);
eb.hook(&eha);
EventD eD{};
EventB eB{};
std::cout << "Firing event D.\n";
eb.fire(&eD); // need to stdout handle EventD handle EventC handle EventA
std::cout << "\nFiring event B.\n";
eb.fire(&eB); // need to stdout handle EventA
return 0;
}