我是C++的新手,并且到了某种程度,我在类上产生了开销。我有一个QTcpSocket并从中读取消息并创建对象,例如MessageJoin,MessagePart,MessageUserData等。我将这些对象发送给我的客户端并显示它们(+做一些UI更新)。
现在是我的问题了。我测试了一些设计技术,但它们都不是很好:
为了更好地理解,我添加了dynamic_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/