将子类的成员函数强制转换为父类

时间:2018-04-20 20:29:37

标签: c++ casting protocols

我正在为游戏网络使用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 {aka void (AbstractPacketHandler::*)(NetworkClient&, NetworkMessage&)}

2 个答案:

答案 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