在C ++中,如何保存抽象类的列表?

时间:2009-09-14 14:52:24

标签: c++ oop inheritance pointers abstract

我有两个实现的类:

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:DCCmdQueueDCReplyQueue,但这只是一些重复的代码。 有任何想法吗? =)

5 个答案:

答案 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