Когда компилятор компилирует класс User
и попадает в строку MyMessageBox
, MyMessageBox
еще не определено. Компилятор понятия не имеет, что MyMessageBox
существует, поэтому не может понять значение вашего ученика.
Вам необходимо убедиться, что MyMessageBox
определено , прежде чем использовать его в качестве участника. Это решается путем изменения порядка определения. Однако у вас есть циклическая зависимость: если вы переместитесь на MyMessageBox
выше User
, то в определении MyMessageBox
имя User
не будет определено!
Что вы можете сделать, это Форвард объявить User
; то есть, объявите это, но не определяйте это. Во время компиляции тип, который объявлен, но не определен, называется неполный тип .
Рассмотрим более простой пример:
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;
}
При прямом объявлении User
, MyMessageBox
все еще может сформировать указатель или ссылку на него:
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;
};
Вы не можете сделать это наоборот: как уже упоминалось, у члена класса должно быть определение. (Причина в том, что компилятор должен знать, сколько памяти занимает User
, и знать, что ему нужно знать размер своих членов.) Если бы вы сказали:
class MyMessageBox;
class User
{
public:
// size not available! it's an incomplete type
MyMessageBox dataMsgBox;
};
Это не сработает, поскольку еще не знает размер.
На заметку об этой функции:
void sendMessage(Message *msg, User *recvr);
Вероятно, не следует брать ни один из них по указателю. Вы не можете отправить сообщение без сообщения, и при этом вы не можете отправить сообщение без пользователя, чтобы отправить его. И обе эти ситуации могут быть выражены передачей нулевого значения в качестве аргумента любому параметру (нулевое значение является абсолютно допустимым значением указателя!)
Вместо этого используйте ссылку (возможно, const):
void sendMessage(const Message& msg, User& recvr);