如何创建基于类型的查找表以在 C++ 中实现多重调度?
我正在尝试创建一个消息系统,其中任何从“Messageable”派生的类都可以根据函数handleMessage() 的重载方式接收消息。例如:
class Messageable {
public:
void takeMessage(Message& message) {
this->dispatchMessage(message);
}
protected:
void bindFunction(std::type_info type, /* Need help here */ func) {
m_handlers[type] = func;
}
void dispatchMessage(Message& message) {
m_handlers[typeid(message)](message);
}
private:
std::map<std::type_info, /*Need help here*/ > m_handlers;
};
class TestMessageable : public Messageable {
public:
TestMessageable() {
this->bindFunction(
typeid(VisualMessage),
void (TestMessageable::*handleMessage)(VisualMessage));
this->bindFunction(
typeid(DanceMessage),
void (TestMessageable::*handleMessage)(DanceMessage));
}
protected:
void handleMessage(VisualMessage visualMessage) {
//Do something here with visualMessage
}
void handleMessage(DanceMessage danceMessage) {
//Do something here with danceMessage
}
};
简而言之,我希望根据任何给定消息的 RTTI 值调用正确版本的handleMessage。
在没有某种整体 switch/case 语句的情况下,如何更好地实现这一点。
I'm attempting to make a messaging system in which any class derived from "Messageable" can receive messages based on how the function handleMessage() is overloaded. For example:
class Messageable {
public:
void takeMessage(Message& message) {
this->dispatchMessage(message);
}
protected:
void bindFunction(std::type_info type, /* Need help here */ func) {
m_handlers[type] = func;
}
void dispatchMessage(Message& message) {
m_handlers[typeid(message)](message);
}
private:
std::map<std::type_info, /*Need help here*/ > m_handlers;
};
class TestMessageable : public Messageable {
public:
TestMessageable() {
this->bindFunction(
typeid(VisualMessage),
void (TestMessageable::*handleMessage)(VisualMessage));
this->bindFunction(
typeid(DanceMessage),
void (TestMessageable::*handleMessage)(DanceMessage));
}
protected:
void handleMessage(VisualMessage visualMessage) {
//Do something here with visualMessage
}
void handleMessage(DanceMessage danceMessage) {
//Do something here with danceMessage
}
};
In a nutshell I want the correct version of handleMessage to be called based on the RTTI value of any given message.
How can I implement this preferably without some sort of monolithic switch/case statement.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您应该研究双重调度模式。请参阅此处的信息。
您应该能够像这样将 VisualMessage 实现为一个类:
然后像这样调用它:
然后它将调用 TestMessageable::handleMessage(VisualMessage & VisualMessage)
这是因为 Message::dispatch 将基于 VisualMessage 类型。然后当VisualMessage::dispatch调用inMessageable.handleMessage(*this)时,它会调用正确的handleMessage,因为*this指针的类型是VisualMessage,而不是Message。
You should look into the Double Dispatch pattern. See information here.
You should be able to implement VisualMessage as a class like such:
and then call it like this:
It will then call TestMessageable::handleMessage(VisualMessage & visualMessage)
This is because Message::dispatch will be based on the VisualMessage type. Then when VisualMessage::dispatch calls inMessageable.handleMessage(*this) it will call the right handleMessage because the type of the *this pointer is VisualMessage, not Message.
要修复您的代码:
这些 static_casts 可以是dynamic_casts,以实现“额外安全”(假设有虚拟函数在运行)。但设计意味着你知道 self 必须是一个指向 S 的指针,因为否则它不会注册这个函数,并且你知道 m 必须引用 T,因为它的 typeid 已经在dispatchMessage中检查过。因此,如果正确使用类,就不会发生失败的转换,而如果确实发生,您所能做的就是调试。
实际上,我认为您可以通过将bindFunction也设置为模板来减少冗长的内容:
然后用以下方式调用它:
但是,您仍然可以看到为什么Steve Rowe的双重调度代码通常是首选......
To fix your code:
Those static_casts could be dynamic_casts for "extra safety" (assuming there are virtual functions kicking around). But the design means you know self must be a pointer to S, because otherwise it wouldn't have this function registered to it, and you know m must refer to a T, because its typeid has already been checked in dispatchMessage. So a failed cast can't happen if the class is used correctly, and all you can do if it does happen is debug.
Actually I think you could cut down the verbiage a bit more by making bindFunction a template too:
Then call it with:
But still, you can see why Steve Rowe's double dispatch code is usually preferred...
这是一个老问题,但 NUClear 库旨在以类似的方式提供快速且类型安全的消息传递回到这个问题的初衷。
全面披露:我是 NUClear 的共同开发者之一
在这种情况下,
TestMessageable
类被实现为NUClear::Reactor
,如下所示:This is an old question but the NUClear library is designed to provide fast and type-safe message passing in a similar vein to the original intent of this question.
Full Disclosure: I am one of the co-developers of NUClear
In this case the
TestMessageable
class is implemented as aNUClear::Reactor
like so:您可以在 Scott Meyers 的 More effective C++ 中找到此类实现,并且
项目 - 31 是您想要的很好地解释了。
You will find such kind of implementation in Scott Meyers' More Effective C++ and
item - 31 is what you want & nicely explained.