Kiedy kompilator kompiluje klasę User
i przechodzi do MyMessageBox
linii, MyMessageBox
nie została jeszcze zdefiniowana. Kompilator nie ma pojęcia, że MyMessageBox
istnieje, więc nie może zrozumieć znaczenia elementu członkowskiego twojej klasy.
Musisz upewnić się, że MyMessageBox
jest zdefiniowany, zanim użyjesz go jako członka. Można to rozwiązać, odwracając kolejność definicji. Masz jednak cykliczną zależność: jeśli przejdziesz MyMessageBox
powyżej User
, to w definicji MyMessageBox
nazwy User
nie zostanie zdefiniowana!
Możesz tylko zadeklarować User
; to znaczy zadeklaruj, ale nie definiuj. Podczas kompilacji typ, który jest zadeklarowany, ale nie zdefiniowany, jest nazywany niekompletnym typem . Rozważmy prostszy przykład:
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;
}
Deklarując do przodu User
, MyMessageBox
nadal może tworzyć wskaźnik lub odniesienie do niego:
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;
};
Nie możesz tego zrobić na odwrót: jak wspomniano, członek klasy musi mieć definicję. (Powodem jest to, że kompilator musi wiedzieć, ile pamięci User
zajmuje i wiedzieć, że musi znać rozmiar jej członków.) Gdybyś miał powiedzieć:
class MyMessageBox;
class User
{
public:
// size not available! it's an incomplete type
MyMessageBox dataMsgBox;
};
Nie zadziała, ponieważ nie zna jeszcze rozmiaru.
Na marginesie, ta funkcja:
void sendMessage(Message *msg, User *recvr);
Prawdopodobnie nie powinien brać żadnego z nich za pomocą wskaźnika. Nie możesz wysłać wiadomości bez wiadomości, ani nie możesz wysłać wiadomości bez użytkownika, do którego można ją wysłać. Obie te sytuacje można wyrazić, przekazując null jako argument do któregokolwiek z parametrów (null to doskonale poprawna wartość wskaźnika!)
Zamiast tego użyj odwołania (prawdopodobnie const):
void sendMessage(const Message& msg, User& recvr);