172

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

jww
  • 97,681
  • 90
  • 411
  • 885
Rakesh K
  • 8,237
  • 18
  • 51
  • 64
  • 28
    The endless times I go this error, just to realize that the import guards generated by the IDE are duplicated – Mazyod Aug 15 '15 at 11:39
  • 3
    Note that you can also get this error if you place an extern reference to a declaration in a .h / .hpp file before the class is defined, even when you have the actual declaration after the .h / .hpp inclusion within the .cpp file. – Owl Mar 19 '16 at 20:01
  • You should also always compile C++ files with command `g++` and not `gcc` – Lorenzo Battilocchi May 08 '19 at 12:29

8 Answers8

253

When the compiler compiles the class User and gets to the MyMessageBox line, MyMessageBox has not yet been defined. The compiler has no idea MyMessageBox exists, so cannot understand the meaning of your class member.

You need to make sure MyMessageBox is defined before you use it as a member. This is solved by reversing the definition order. However, you have a cyclic dependency: if you move MyMessageBox above User, then in the definition of MyMessageBox the name User won't be defined!

What you can do is forward declare User; that is, declare it but don't define it. During compilation, a type that is declared but not defined is called an incomplete type. Consider the simpler example:

struct foo; // foo is *declared* to be a struct, but that struct is not yet defined

struct bar
{
    // this is okay, it's just a pointer;
    // we can point to something without knowing how that something is defined
    foo* fp; 

    // likewise, we can form a reference to it
    void some_func(foo& fr);

    // but this would be an error, as before, because it requires a definition
    /* foo fooMember; */
};

struct foo // okay, now define foo!
{
    int fooInt;
    double fooDouble;
};

void bar::some_func(foo& fr)
{
    // now that foo is defined, we can read that reference:
    fr.fooInt = 111605;
    fr.foDouble = 123.456;
}

By forward declaring User, MyMessageBox can still form a pointer or reference to it:

class User; // let the compiler know such a class will be defined

class MyMessageBox
{
public:
    // this is ok, no definitions needed yet for User (or Message)
    void sendMessage(Message *msg, User *recvr); 

    Message receiveMessage();
    vector<Message>* dataMessageList;
};

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

You cannot do this the other way around: as mentioned, a class member needs to have a definition. (The reason is that the compiler needs to know how much memory User takes up, and to know that it needs to know the size of its members.) If you were to say:

class MyMessageBox;

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

It wouldn't work, since it doesn't know the size yet.


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 are expressible by passing null as an argument to either parameter (null is a perfectly valid pointer value!)

Rather, use a reference (possibly const):

 void sendMessage(const Message& msg, User& recvr);
kilojoules
  • 9,768
  • 18
  • 77
  • 149
GManNickG
  • 494,350
  • 52
  • 494
  • 543
  • 5
    +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 Jan 25 '10 at 15:38
  • 15
    @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`... – GManNickG Jan 25 '10 at 15:41
12
  1. Forward declare User
  2. Put the declaration of MyMessageBox before User
Brian R. Bondy
  • 339,232
  • 124
  • 596
  • 636
4

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
  • 173,980
  • 10
  • 155
  • 350
  • Swapping won't work as `MyMessageBox` has `User` type in it's method declaration. – Amarghosh Jan 25 '10 at 15:33
  • 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 Jan 26 '10 at 08:46
  • Yeah, but simply swapping the definitions won't work as `User` type is not declared yet. – Amarghosh Jan 26 '10 at 10:28
4

In my case, it turned out that this very uninformative error was caused by a circular dependency. Instead of

// A.hpp
#include "B.hpp"

class A {
    B b;
}

// B.hpp
#include "A.hpp"

class B {
    A a;
}

I changed the second file to

// B.hpp
class A;

class B {
    A a;
}

... and all the compiler errors, as well as the sudden lack of syntax highlighting in my IDE, disappeared.

I did need to later put a #include "A.hpp" at the top of the B.cpp file, but that's fine, because there's no circular dependency in that case (B.cpp -> A.hpp -> B.hpp -> /).

Mew
  • 368
  • 1
  • 11
3

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
  • 7,844
  • 1
  • 28
  • 32
3

On a related note, if you had:

    class User; // let the compiler know such a class will be defined

    class MyMessageBox
    {
    public:
        User* myUser;
    };

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

Then that would also work, because the User is defined in MyMessageBox as a pointer

2

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
  • 20,042
  • 4
  • 30
  • 28
1

It is always encouraged in C++ that you have one class per header file, see this discussion in SO [1]. GManNickG answer's tells why this happen. But the best way to solve this is to put User class in one header file (User.h) and MyMessageBox class in another header file (MyMessageBox.h). Then in your User.h you include MyMessageBox.h and in MyMessageBox.h you include User.h. Do not forget "include gaurds" [2] so that your code compiles successfully.

Community
  • 1
  • 1
Chehadeh
  • 11
  • 2