В C ++, как я могу хранить список абстрактных классов? - PullRequest
3 голосов
/ 14 сентября 2009

У меня есть два реализованных класса:

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, но это просто дублированный код для чего-то тривиального. Есть идеи? =)

Ответы [ 4 ]

14 голосов
/ 14 сентября 2009

Вы не можете создать экземпляр объекта, потому что он абстрактный, как вы сказали. Однако вы можете хранить вектор указателей на класс DCMessage, который будет работать, вам просто нужно добавить адрес памяти, а не объект, когда он помещается в список.

vector<DCMessage*> queue;

DCCmd* commandObject = new DCCmd(...params...);
queue.push_back(commandObject);

BYTE* params = queue[0]->getParams();
10 голосов
/ 14 сентября 2009

Вы хотите вектор указателей DCMessage:

vector<DCMessage*> messages;
messages.push_back(new DCCmd(blah));

Полиморфизм в C ++ работает только через указатели и ссылки, и вы не можете использовать ссылки для этого. Итак, указатели это.

3 голосов
/ 14 сентября 2009

(проголосовал за Келикса, но я думаю, что это требует дополнительной проработки)

Что вы хотите сделать, так это создать вектор элементов, который может иметь любой объект, производный от вашего абстрактного класса, верно? Когда вы говорите vector <DCMessage>, вы вместо этого запрашиваете вектор элементов класса DCMessage. Вы не можете иметь их, так как это абстрактный класс.

Если вместо этого вы запросите vector <DCMessage *>, то вы можете предоставить указатели на объекты любого класса, производного от DCMessage, и получите динамическую (во время выполнения) диспетчеризацию для правильной реализации ваших абстрактных подпрограмм при вызове во время выполнения.

2 голосов
/ 14 сентября 2009

Если вам нужен полиморфизм, вам нужны указатели в C ++, поэтому используйте деку указателей на абстрактный тип (при условии, что это очередь FIFO, а не LIFO). Затем у вас возникает проблема управления тем, кому принадлежат сообщения в очереди.

Однако C ++ - это не только ОО, и в C ++ есть идиомы для записи объектов в потоки; если очередь сообщений просто перенаправляет их в порт tcp или имеет похожее поведение, вы можете использовать эти идиомы и копировать данные, а не хранить ссылку на объект. Если вы в любом случае реализуете методы для маршаллинга ваших объектов сообщений в двоичный файл и из него, вы можете сэкономить время, если ваша очередь является просто буферизованным потоком.

...