Cuando el compilador compila la clase Usery llega a la MyMessageBoxlínea, MyMessageBoxaún no se ha definido. El compilador no tiene idea de que MyMessageBoxexiste, por lo que no puede entender el significado de su miembro de clase.
Debe asegurarse de que MyMessageBoxesté definido antes de usarlo como miembro. Esto se resuelve invirtiendo el orden de definición. Sin embargo, tiene una dependencia cíclica: si se mueve hacia MyMessageBoxarriba User, ¡en la definición del MyMessageBoxnombre Userno se definirá!
Lo que puede hacer es declarar hacia adelante User ; es decir, declararlo pero no definirlo. Durante la compilación, un tipo que se declara pero no se define se denomina tipo incompleto . Considere el ejemplo más simple:
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;
}
Al declarar hacia adelante User, MyMessageBoxaún puede formar un puntero o hacer referencia a él:
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;
};
No puede hacer esto al revés: como se mencionó, un miembro de la clase necesita tener una definición. (La razón es que el compilador necesita saber cuánta memoria Userocupa y saber que necesita saber el tamaño de sus miembros). Si tuviera que decir:
class MyMessageBox;
class User
{
public:
// size not available! it's an incomplete type
MyMessageBox dataMsgBox;
};
No funcionaría, ya que aún no conoce el tamaño.
En una nota al margen, esta función:
void sendMessage(Message *msg, User *recvr);
Probablemente no debería tomar ninguno de esos por puntero. No puede enviar un mensaje sin un mensaje, ni puede enviar un mensaje sin un usuario a quien enviarlo. Y ambas situaciones se pueden expresar pasando nulo como argumento a cualquier parámetro (¡nulo es un valor de puntero perfectamente válido!)
Más bien, use una referencia (posiblemente constante):
void sendMessage(const Message& msg, User& recvr);