5

我有真正的消息类,例如

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()。但是返回类型是什么?这是我想不通的?或者也许我需要重新考虑。

编辑感谢您的所有回复。我了解了多次调度等等。

最后我决定这样做:-

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* 。

4

2 回答 2

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 
   }
};
于 2012-11-08T17:25:45.597 回答
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 的形式支持一些简单的自省功能。默认情况下,这不一定会编译到您的二进制文件中;它可能需要额外的编译器标志(-frtti在 GNU 领域)。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&OE 等的代码;-)

于 2012-11-08T17:45:18.100 回答