我有两个实现的类:
class DCCmd :
public DCMessage
class DCReply :
public DCMessage
两者都是双向发送和接收的协议消息。
现在在协议实现中我需要创建一个消息队列,但是DCMessage
是抽象的,它不会让我做这样的事情:
class DCMsgQueue{
private:
vector<DCMessage> queue;
public:
DCMsgQueue(void);
~DCMsgQueue(void);
bool isEmpty();
void add(DCMessage &msg);
bool deleteById(unsigned short seqNum);
bool getById(unsigned short seqNum, DCMessage &msg);
};
问题是,正如编译器所说,“DCMessage无法实例化”,因为它有一个纯粹的抽象方法:
virtual BYTE *getParams()=0;
删除=0
并在DCMessage.cpp
中添加空花括号可以解决问题,但这只是一个黑客攻击。
另一个解决方案是我应该制作两个DCMsgQueues:DCCmdQueue
和DCReplyQueue
,但这只是一些重复的代码。
有任何想法吗? =)
答案 0 :(得分:14)
您无法实例化对象,因为它是抽象的,如您所说。但是,你可以拥有一个指向DCMessage类的指针向量,它只需要添加内存地址,而不是将对象推送到列表时。
vector<DCMessage*> queue;
DCCmd* commandObject = new DCCmd(...params...);
queue.push_back(commandObject);
BYTE* params = queue[0]->getParams();
答案 1 :(得分:10)
您需要一个DCMessage指针向量:
vector<DCMessage*> messages;
messages.push_back(new DCCmd(blah));
C ++中的多态性只能通过指针和引用来工作,并且您不能使用引用。所以,它是指针。
答案 2 :(得分:3)
(投票支持Kelix,但我认为这需要更多详细说明)
你要做的是创建一个元素向量,可以是从抽象类派生的任何对象,对吧?当您说vector <DCMessage>
时,您要求提供DCMessage类的元素向量。你不能拥有它们,因为那是一个抽象类。
如果您要求vector <DCMessage *>
,那么您可以提供指向从DCMessage派生的任何类的对象的指针,并在运行时调用时将动态(运行时)调度到正确的抽象例程实现。< / p>
答案 3 :(得分:2)
如果你想要多态,你需要在C ++中使用指针,所以会使用一个指向抽象类型的指针(假设它是一个FIFO队列而不是一个LIFO)。然后,您遇到了管理谁拥有队列中的消息的问题。
但是,C ++不只是关于OO,而且C ++中有用于将对象写入流的习惯用法;如果消息队列只是将它们转发到tcp端口或具有类似的行为,您可能希望使用这些惯用法并复制数据而不是存储对象的引用。如果你正在实现将消息对象与二进制文件进行编组的技术,那么如果你的队列只是一个缓冲流,你最终可能会节省一些麻烦。
答案 4 :(得分:0)
其他答案指出,您只能有抽象类的指针。当在类似列表的容器中使用它时,删除元素后,您还必须手动删除它们的内存,因为容器操作仅对指针值本身起作用,而对指针值不起作用。
在cpp-11中,您可以使用unique_ptr<some_type>
之类的包装器来实现目标,而无需直接处理指针:
list<unique_ptr<your_abstract_class>> someList;
someList.push_back(make_unique<your_derived_class>()); // will create new instance
someList.push_back(make_unique<your_other_derived_class>());
someList.pop_front(); // will remove the instance and automatically call its destructor