tags:

views:

339

answers:

5

Hi,

I have two classes declared as below:

class User
{
public:
 MyMessageBox dataMsgBox;
};

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

When I try to compile it using gcc, it gives the following error: 'MyMessageBox does not name a type'. Please help me in this regard.

Thanks, Rakesh.

+13  A: 

When the compiler compiles the class User, and gets to the MyMessageBox line, MyMessageBox has not yet been defined. It has no idea it exists.

You need to make sure MyMessageBox is defined before you use it as a member. This is solved by reversing the definition order.

Now, you have a cyclic dependency. What you can do is forward declare User so message box can still take a pointer or reference to it, without knowing the full definition:

class User; // let the compiler know such a class will exist

class MyMessageBox
{
public:
 void sendMessage(Message *msg, User *recvr); // that's ok
 Message receiveMessage();
 vector<Message> *dataMessageList;
};

class User
{
public:
 MyMessageBox dataMsgBox; // also ok, since it's defined
};

You cannot do this the other way around. The reason is for the compiler to know how much memory User takes up, it needs to know the size of it's members. If you were to say:

class MyMessageBox;

class User
{
public:
 MyMessageBox dataMsgBox; // size not available! it's an incomplete type
};

It wouldn't work, since it doesn't know the size yet. (Because it has no full definition.)


On a side note, this function:

 void sendMessage(Message *msg, User *recvr);

Probably shouldn't take either of those by pointer. You can't send a message without a message, nor can you send a message without a user to send it to. And both of those situations come true if you pass null to the function.

Rather, use a reference (possibly const):

 void sendMessage(const Message& msg, User& recvr);

So it's both required to give both parameters, and easier to use.

GMan
+1 Learned something today - I thought forward declaring `MyMessageBox` would've been enough. What if `MyMessageBox` had a variable of type `User` too - would that be a deadlock?
Amarghosh
@Amargosh: Yes, it would be impossible. Logically impossible as well, since `User` would have a `MessageBox` which would have a `User`, which would have a `MessageBox` which would have a `User`, which would have a `MessageBox` which would have a `User`, which would have a `MessageBox` which would have a `User`...
GMan
Thanks GMan. I have made changes to my code as you suggested and it works fine now.
Rakesh K
@Rakesh: No problem.
GMan
A: 

You must declare the prototype it before using it:

class User;

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

class User
{
public:
 MyMessageBox dataMsgBox;
};

edit: Swapped the types

Alex LE
No, won't work. Class members must be defined, not forqward declared.
MSalters
A: 

C++ compilers process their input once. Each class you use must have been defined first. You use MyMessageBox before you define it. In this case, you can simply swap the two class definitions.

MSalters
Swapping won't work as `MyMessageBox` has `User` type in it's method declaration.
Amarghosh
Don't work because MyMessageBox also uses the User class.
Alex LE
Actually, that definition doesn't _use_ class `User`. Important distinction, because that means class User only needs to be _declared_ at that point, not _defined_. But see GMan's extensive post.
MSalters
Yeah, but simply swapping the definitions won't work as `User` type is not declared yet.
Amarghosh
+1  A: 
  1. Forward declare User
  2. Put the declaration of MyMessageBox before User
Brian R. Bondy
+1  A: 

You need to define MyMessageBox before User -- because User include object of MyMessageBox by value (and so compiler should know its size).

Also you'll need to forward declare User befor MyMessageBox -- because MyMessageBox include member of User* type.

Alexander Poluektov