我正在为游戏网络使用tcp套接字制作协议,我想抽象我的数据包处理程序。 这是我的代码:
class AbstractPacketHandler;
using handler_t = void (AbstractPacketHandler::*)(NetworkClient &, NetworkMessage &);
using handlers_t = std::unordered_map<int32_t, handler_t>;
class AbstractPacketHandler {
public:
void parse_packet(NetworkClient &client, NetworkMessage &msg);
protected:
virtual void init(handlers_t &handlers) = 0;
private:
AbstractPacketHandler() = default;
handlers_t _handlers;
};
低于实施class ServerHandler: public AbstractPacketHandler
void ServerHandler::init(handlers_t &handlers) {
handlers[HelloConnectMessage::PROTOCOL_ID] = reinterpret_cast<handler_t>(&ServerHandler::onHello));
}
void ServerHandler::onHello(NetworkClient &, HelloConnectMessage &msg) {
printf("deserialized hellomsg: %d\n", msg.getHelloVar());
}
这编译但我不确定它是否在运行时工作。问题来自于我尝试reinterpret_cast
指向父类AbstractPacketHandler
的成员函数的指针
实际上,using handler_t = void (AbstractPacketHandler::*)(NetworkClient &, NetworkMessage &);
是指向AbstractPacketHandler
成员函数的成员函数的指针
由于onHello
是我的子类ServerHandler
的函数,我认为它无法在运行时找到该函数。
我错了吗?我怎么能解决它以保持抽象?
修改
从评论中,我尝试静态转换,看看代码是否应该与它一起使用,我得到编译错误:
错误:类型为
void (ServerHandler::*)(NetworkClient&, HelloConnectMessage&)’
的static_cast无效 'handler_t {akavoid (AbstractPacketHandler::*)(NetworkClient&, NetworkMessage&)
}
答案 0 :(得分:1)
这&#34;工作&#34;只是因为,在这种特定情况下,ServerHandler
与其自己的AbstractPacketHandler
内部实例共享其地址,因此当使用AbstractPacketHandler this
指针调用处理程序时,它会被有效地重新解释为ServerHandler,它恰好排列正确(幸运的是)。
但是,只有在不涉及多重继承的情况下,这才有效。如果你有以下情况,那么一切都会破裂:
class ServerHandler: public Something, public AbstractPacketHandler {};
我怎么能解决它以保持抽象?
您最好的选择是为您的处理程序使用std::function<>
,如下所示:
using handler_t = std::function<void(NetworkClient &, NetworkMessage &)>;
...
void ServerHandler::init(handlers_t &handlers) {
handlers[HelloConnectMessage::PROTOCOL_ID] =
[this](NetworkClient& a, NetworkMessage& b) {onHello(a, b);};
}
这确实增加了一个额外的间接层,但它更好(你甚至可以完全摆脱这个模型的继承!)
答案 1 :(得分:0)
问题是你正在使用指向成员函数的指针。这些是C ++最糟糕的想法之一,基本上不应该使用。使用{% extends 'base.html' %}
{% block content %}
{% for category in categories %}
<h1>{{ category }}</h1>
{% for product in category.products_set.all %}
<p>{{ product }}</p>
{% endfor %}
{% endfor %}
{% endblock %}
。
真的,我觉得这里的控制很奇怪。您所做的只是a)解析数据包和b)调用函数。类和继承似乎是多余的。为什么不使std::function<void(NetworkClient&, NetworkMessage&)>
成为一个返回你正在键入的int32_t的自由函数,然后调用者可以直接调用相应的函数?在这种情况下,即使你想保留一个抽象处理程序类的概念(即使它没有任何值,我建议删除),即使没有任何间接也能使它工作是微不足道的。 E.G。
parse_packet