views:

288

answers:

4

I have two implemented classes:

class DCCmd :
    public DCMessage

class DCReply :
    public DCMessage

Both are protocol messages that are sent and received both ways.

Now in the protocol implementation I'd need to make a message queue, but with DCMessage being abstract it won't let me do something like this:

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);
};

The problem is that, as the compiler puts it, "DCMessage cannot be instantiated", since it has a pure abstract method:

virtual BYTE *getParams()=0;

Removing the =0 and putting empty curly braces in DCMessage.cpp fixes the problem, but it is just a hack.

The other solution is that I should make two DCMsgQueues: DCCmdQueue and DCReplyQueue, but this is just duplicated code for something trivial. Any ideas? =)

+13  A: 

You cannot instantiate the object because it is abstract as you said. You can however hold a vector of pointers to the DCMessage class which will work, you just need to add the memory address and not the object when pushing it on to the list.

vector<DCMessage*> queue;

DCCmd commandObject = ...;
queue.push_back(&commandObject);

BYTE* params = queue[0]->getParams();
Nat Ryall
Just make sure you aren't storing the address of a stack-allocated object (well, any object that will be out of scope before it's removed from the vector).
GMan
Remember to delete your pointers in your destructor; and you'll probably want to implement the copy constructor and assignment operator so you get a deep copy should the need arise.
Ron Warholic
This works; however, my commands are getting quickly out of scope so I neeed to take this into consideration. I am a while from having a debuggable source, so many thanks for now.
Omer Sabic
+10  A: 

You want a vector of DCMessage pointers:

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

Polymorphism in C++ only works through pointers and references, and you can't use references for this. So, pointers it is.

Warren Young
Polymorphism will work with references. You cannot store them, however.
GMan
What are you saying that's different from what I wrote?
Warren Young
For some reason when I read it, I skipped over "and references". Combined with "and you can't use references for this", I thought there was an error. I shamefully retract my comment. :)
GMan
+2  A: 

If you want polymorphism, you need pointers in C++, so would use a deque of pointers to the abstract type ( assuming it's a FIFO queue rather than a LIFO ). You then have the problem of managing who owns the messages in the queue.

However, C++ isn't just about OO, and there are idioms in C++ for writing objects to streams; if the message queue just forwards them to a tcp port or has a behaviour similar to , you might want to use those idioms and copy the data rather than storing a reference to the object. If you're implementing techniques to marshall your message objects to and from binary anyway, you might end up saving yourself some bother if your queue is just a buffered stream.

Pete Kirkham
I need random access to the elements in the queue and I read at cplusplus.com reference that vectors are a better choice for that.Just buffering won't work for reasons that are in the protocol specs.
Omer Sabic
If you need random *indexing* into the "queue", then yes, vectors are better. If you just need to access elements in the middle once they are found (by iterating through the structure), then it doesn't really matter.
T.E.D.
""A deque [1] is very much like a vector: like vector, it is a sequence that supports random access to elements, constant time insertion and removal of elements at the end of the sequence, and linear time insertion and removal of elements in the middle.The main way in which deque differs from vector is that deque also supports constant time insertion and removal of elements at the beginning of the sequence [2]. "" http://www.sgi.com/tech/stl/Deque.html
Pete Kirkham
+3  A: 

(Voted Kelix up, but I think this needs more elaboration)

What you are looking to do is create a vector of elements that can be of any object derived from your abstract class, right? When you say vector <DCMessage>, you are instead asking for a vector of elements of class DCMessage. You can't have them, as that is an abstract class.

If you instead ask for vector <DCMessage *>, then you can supply pointers to objects of any class derived from DCMessage, and will get dynamic (runtime) dispatch to the correct implementation of your abstract routines when invoked at runtime.

T.E.D.
Thanks, but don't you mean that I "supply references to objects"? This is confusing.
Omer Sabic
T.E.D.