我有真实的消息类,例如
class Specific1Message {
//various functions to get different types of data
};
class Specific2Message {
//various functions to get different types of data
};
我无法改变。
我正在重写一个编码和解码这些消息的软件工具。它决定在运行时解码/编码哪些消息。
从要重播的文本文件中检索特定消息的负载以模仿真实系统。消息临时存储在std :: list中。为了使新/删除生命周期更加健壮,我被要求使用智能指针。
我对这些消息的第一个想法是做这样的事情: -
class proto_msg : public ref_type {
public:
}
// ref_type是一个智能指针类
class Specific1msg : public proto_msg {
public:
Specific1Message m_msg; //instance of specific 1 message - composition
};
但是我的工具中有函数,它将proto_msg *作为参数。所以我想要到达Specific1Message(例如)我会这样做:
int SpecificMessageHandler::EncodeMsg(proto_msg* msg, unsigned char* buffer, int size)
但是如何检索一个Specific1Message? msg-> GetMsg() - 但是如何定义这个方法?会有什么回报?
我需要在基类中定义GetMsg()。但是什么是返回类型?那是我无法理解的?或许我需要重新思考。
EDIT 谢谢你的回复。我在其他事情中学到了多次派遣。
最后我决定这样做: -
class realproto {
public:
const char* getName() const { return "realproto"; }
};
class real2ndproto {
public:
const char* get2Name() const { return "real2ndproto"; }
};
template<typename T>
class ProtoWrapper : public ref_type {
public:
ProtoWrapper(T* real) : m_msg(real) {}
~ProtoWrapper() { delete m_msg; } //cannot have smart ptr on real_proto - so do this way
T* getMsg() { return m_msg; }
private:
T* m_msg;
};
然后像这样打电话
ref_ptr<ProtoWrapper <realproto> > msg2 = new ProtoWrapper<realproto>(new realproto);
realproto* pr1 = msg2->getMsg(); //if need underlying protocol
这应该允许我删除所需的代码更少的void *。
答案 0 :(得分:4)
我能想到的唯一选择是模板+双重调度
class proto_msg : public ref_type{
public:
virtual int call_encode (SpecificMessageHandler*, unsigned char* buffer, int size) = 0;
};
template <class M>
class SpecificMesssageTpl : public proto_msg
{
public:
int call_encode (SpecificMessageHandler* handler, unsigned char* buffer, int size)
{
return handler->EncodeMsgSpecific (m_msg, buffer, size);
}
private:
M m_msg; //instance of specific 1 message - composition
};
class SpecificMessageHandler
{
public:
int SpecificMessageHandler::EncodeMsg(proto_msg* msg, unsigned char* buffer, int size)
{
return msg->call_encoder (this, buffer, size);
}
int SpecificMessageHandler::EncodeMsgSpecific(Specific1Message * msg, unsigned char* buffer, int size)
{
// encode Specific1Message
}
int SpecificMessageHandler::EncodeMsgSpecific(Specific2Message * msg, unsigned char* buffer, int size)
{
// encode Specific2Message
}
};
答案 1 :(得分:0)
没有一大堆干净,简单的方法可以做到这一点。但是,如果您愿意在略显不雅的代码上妥协,那么有一些可能性。
那么proto_msg
如何更新如下:
class proto_msg : public ref_type
{
public:
virtual int message_type() = 0;
}
它的子类更新如下:
class Specific1msg : public proto_msg
{
public:
static const int message_id = 1;
virtual int message_type() { return message_id; }
Specific1Message m_msg; //instance of specific 1 message - composition
};
然后你可以使用if语句来选择一个处理程序:
// proto_msg a_message;
if (a_message.message_type() == Specific1msg::message_id)
{
Specific1msg specific_message = (Specific1msg)a_message;
// do something with specific_message.msg
}
实际上,C ++确实以运行时类型信息或RTTI的形式支持一些简单的内省功能。默认情况下,这不一定会编译到您的二进制文件中;它可能需要额外的编译器标志(GNU land中的-frtti
)。 RTTI允许您使用dynamic_cast
执行类型转换操作,可以正常处理故障。
// proto_msg* a_message
Specific1Message* specific_message = dynamic_cast<Specific1Msg*>(a_message));
if (message != nullptr)
{
// Do something with specific_message.msg
}
等等。还有很多其他方法可以做到这一点,我认为总的来说我更喜欢Aleguna的双重调度模板魔法,但这种机制应该是非常直接的,对任何人来说都很简单!
代码未经测试,未编译,E&amp; OE等; - )