Quando il compilatore compila la classe User
e arriva alla MyMessageBox
riga, MyMessageBox
non è stato ancora definito. Il compilatore non ha idea che MyMessageBox
esista, quindi non può capire il significato del membro della classe.
Devi assicurarti che MyMessageBox
sia definito prima di usarlo come membro. Questo viene risolto invertendo l'ordine di definizione. Tuttavia, hai una dipendenza ciclica: se ti sposti MyMessageBox
sopra User
, allora nella definizione del MyMessageBox
nome User
non verrà definito!
Quello che puoi fare è dichiarare in avanti User
; cioè dichiaralo ma non definirlo. Durante la compilazione, un tipo dichiarato ma non definito viene chiamato tipo incompleto . Considera l'esempio più semplice:
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;
}
Con la dichiarazione in avanti User
, MyMessageBox
può ancora formare un puntatore o un riferimento ad esso:
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;
};
Non puoi farlo al contrario: come accennato, un membro della classe deve avere una definizione. (Il motivo è che il compilatore ha bisogno di sapere quanta memoria User
occupa e di sapere che ha bisogno di conoscere la dimensione dei suoi membri.) Se dovessi dire:
class MyMessageBox;
class User
{
public:
// size not available! it's an incomplete type
MyMessageBox dataMsgBox;
};
Non funzionerebbe, poiché non conosce ancora le dimensioni.
In una nota a margine, questa funzione:
void sendMessage(Message *msg, User *recvr);
Probabilmente non dovrebbe prendere nessuno di questi per puntatore. Non puoi inviare un messaggio senza un messaggio, né puoi inviare un messaggio senza un utente a cui inviarlo. Ed entrambe queste situazioni sono esprimibili passando null come argomento a entrambi i parametri (null è un valore puntatore perfettamente valido!)
Piuttosto, usa un riferimento (possibilmente const):
void sendMessage(const Message& msg, User& recvr);