views:

146

answers:

5

Hi,

I am using two classes in my C++ application. The code is as follows:

class MyMessageBox
{
public:
    void sendMessage(Message *msg, User *recvr);
    Message receiveMessage();
    list<Message> dataMessageList;
};

class User
{
public:
    MyMessageBox *dataMsgBox;
};

The msg is a pointer to a derived class object of Message class. I have implemented the function sendMessage as follows:

void MyMessageBox::sendMessage(Message *msg, User *recvr)
{
    Message &msgRef = *msg;
    recvr->dataMsgBox->dataMessageList.push_back(msgRef);
}

When I compile this code, I get the following error: undefined reference to `vtable for Message'. Please help me out to solve this issue.

Thanks, Rakesh.

A: 

I think this is a slightly contrived error message suggesting that you've not implemented a constructor for your message class. Have a look here and here on SO...

Given that you're trying to pass a pointer to a list of objects, the compiler is probably complaining that it has no way to convert Message* to Message. Try changing your list to a list of Message* as Kylotan suggests.

Is it a compile or a link error?

Jon Cage
Not in this case. There is no good reason for implementing a *virtual* constructor in here.
PierreBdR
+4  A: 

I don't know what you're trying to do with that msgRef, but it's wrong. Are you an ex-Java programmer, by any chance?

If Message is a base class for derivatives of Message, you need to store pointers in the list. Change list<Message> to list<Message*>; and push_back(msgRef) should become push_back(msg), removing the msgRef code entirely.

Also, as a matter of style, it's a bad idea to chain lots of -> operators together. It's better to implement a method on User in this case that adds a Message to its own list and call that.

Kylotan
Thanks Kylotan. I changed my code like you said, and it compiles fine now.
Rakesh K
@Rakesh K - don't forget that you need extra cleanup code for the list if you have a list<Message \*>. The list destructor will _not_ delete the elements pointed to by the pointer. You have to delete them manually yourself or (recommended) use something like boost::shared_ptr<> to handle them as value objects that get destroyed when the last reference to them is destroyed. If you don't use either shared_ptr or clean up the list yourself, you will end up with a resource leak.
Timo Geusch
A: 

If you want to handle subclassed Messages, you need to use a list of Message pointers rather than Message objects, and manage their lifetime. For convenience, I'd suggest making it

list< boost::shared_ptr<Message> > datamessageList

using the boost library. (And not to offend, but you do need to read up a bit more on C++ and pointers: it looks like you tried various permutations of your code until you got something that compiled...)

Pontus Gagge
+1  A: 

For starters, if you want to store a polymorphic object in a standard C++ container, you should store a pointer to the object and not an object of the base class. If you don't, you run into object slicing issues. Also, do yourself a favour and wrap the pointer in a smart pointer to prevent resource leaks - I would recommend boost::shared_ptr<>.

Given that you haven't shown us the code for Message, we can but guess what the problem is. As it's referring to a vtable, chances are that:

  • You didn't declare any of Message's class members as virtual. Starting with the destructor would be a good idea
  • You forgot to link against an object file that contains the compiled code for Message

By the way, creating the additional reference in sendMessage() is not necessary and IMHO doesn't exactly help readability. Just dereference the msg pointer in your call to push_back().

Timo Geusch
A: 

As some are proposing better solutions: check out std::queue or std::deque to queue your messages. So now you have:

std::queue<std::tr1::shared_ptr<Message> > dataMessageQueue;
stefaanv