我是C++的新手,并且到了某种程度,我在类上产生了开销。我有一个QTcpSocket并从中读取消息并创建对象,例如MessageJoin,MessagePart,MessageUserData等。我将这些对象发送给我的客户端并显示它们(+做一些UI更新)。

现在是我的问题了。我测试了一些设计技术,但它们都不是很好:

  • 将信号对象/插槽连接中消息对象的每个参数传递给客户端-开销很小,但不是那么好看
  • 为每个消息类型(messageJoinReceived,messageNoticeReceived等)创建一个方法。
  • 创建一个方法,并使用dynamic_cast转换每个类并对其进行测试

  • 为了更好地理解,我添加了dynamic_cast版本。可以这么说,该代码看起来丑陋且无法使用。 我的问题是:
  • 是否有更好的方法来做到这一点?(a)dynamic_cast
  • 是否有另一种方法(例如设计模式)来解决此类问题?也许在类中添加一个方法并返回类型或类似
  • 我了解了访客模式。这种模式仅适用于Getter / Setter方法中的动态对象类型吗?

  • 一些注意事项
  • 我可以使用RTTI
  • Speed没什么大不了的。干净易懂的代码更重要
  • 我使用Qt并有可能使用qobject_cast和信号/插槽

  • 这是我的代码(Pastebin-Link):
    // Default class - contains the complete message (untouched)
    class Message
    {
    public:
        QString virtual getRawMessage() { return dataRawMessage; }
    protected:
        QString dataRawMessage;
    };
    
    // Join class - cointains the name of the joined user and the channel
    class MessageJoin : public Message
    {
    public:
        MessageJoin(const QString &rawmessage, const QString &channel, const QString &user)
        {
            dataRawMessage = rawmessage;
            dataChannel = channel;
            dataUser = user;
        }
    
        QString getChannel() { return dataChannel; }
        QString getUser(){ return dataUser; }
    
    private:
        QString dataChannel;
        QString dataUser;
    };
    
    // Notice class - contains a notification message
    class MessageNotice : public Message
    {
    public:
        MessageNotice(const QString &rawmessage, const QString &text)
        {
            dataRawMessage = rawmessage;
            dataText = text;
        }
    
        QString getText() { return dataText;}
    
    private:
        QString dataText;
    };
    
    // Client code - print message and update UI
    void Client::messageReceived(Message *message)
    {
        if(message)
        {
            MessageJoin *messagejoin;
            MessagePart *messagepart;
            MessageNotice *messagenotice;
            if((messagejoin = dynamic_cast<MessageJoin *>(message)) != 0)
            {
                qDebug() << messagejoin->getUser() << " joined " << messagejoin->getChannel();
                // Update UI: Add user
            }
            else if((messagenotice = dynamic_cast<MessageNotice *>(message)) != 0)
            {
                qDebug() << messagenotice->getText();
                // Update UI: Display message
            }
            else
            {
                qDebug() << "Cannot cast message object";
            }
            delete message; // Message was allocated in the library and is not used anymore
        }
    }
    

    最佳答案

    这看起来与the expression problem和AFAIK非常相似,如果要添加新消息和新方法来处理它们,则无法避免强制转换。但是,对必要的运行时内容进行更多令人愉悦的包装并不难。只需使用typeid创建从消息类型到相应处理程序的映射。
    #include <functional>#include <typeindex>#include <typeinfo>#include <unordered_map>typedef std::function<void(Message *)> handler_t;typedef std::unordered_map< std::type_index, handler_t> handlers_map_t;template <class T, class HandlerType>handler_t make_handler(HandlerType handler){ return [=] (Message *message) { handler(static_cast<T *>(message)); };}template <class T, class HandlerType>void register_handler( handlers_map_t &handlers_map, HandlerType handler){ handlers_map[typeid(T)] = make_handler<T>(handler);}void handle(handlers_map_t const &handlers_map, Base *message){ handlers_map_t::const_iterator i = handlers_map.find(typeid(*message)); if (i != handlers_map.end()) { (i->second)(message); } else { qDebug() << "Cannot handle message object"; }}
    然后注册特定消息类型的处理程序:
    handlers_map_t handlers_map;register_handler<MessageJoin>( handlers_map, [] (MessageJoin *message) { qDebug() << message->getUser() << " joined " << message->getChannel(); // Update UI: Add user });register_handler<MessageNotice>( handlers_map, [] (MessageNotice *message) { qDebug() << message->getText(); // Update UI: Display message });
    现在您可以处理消息:
    // simple testMessage* messages[] ={ new MessageJoin(...), new MessageNotice(...), new MessageNotice(...), new MessagePart(...),};for (auto m: messages){ handle(handlers_map, m); delete m;}
    当然,您可能需要进行一些改进,例如将处理程序内容包装到可重用的类中,使用QT或增强信号/插槽,以便您可以为一条消息使用多个处理程序,但是核心思想是相同的。

    关于c++ - 避免对派生类(Cast Derived类)进行dynamic_cast,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/17547379/

    10-10 04:23