Errore “X non nomina un tipo” in C ++

Ho due classi dichiarate come di seguito:

class User { public: MyMessageBox dataMsgBox; }; class MyMessageBox { public: void sendMessage(Message *msg, User *recvr); Message receiveMessage(); vector *dataMessageList; }; 

Quando provo a compilarlo usando gcc, si dà il seguente errore:

MyMessageBox non nomina un tipo

Quando il compilatore compila l’ User della class e arriva alla riga MyMessageBox , MyMessageBox non è stato ancora definito. Il compilatore non ha idea di MyMessageBox , quindi non può capire il significato del membro della tua class.

È necessario assicurarsi che MyMessageBox sia definito prima di utilizzarlo come membro. Questo è risolto invertendo l’ordine di definizione. Tuttavia, si ha una dipendenza ciclica: se si sposta MyMessageBox sopra User , quindi nella definizione di MyMessageBox il nome User non sarà definito!

Quello che puoi fare è inoltrare la dichiarazione User ; cioè dichiararlo ma non definirlo. Durante la compilazione, un tipo dichiarato ma non definito viene chiamato un 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; } 

In avanti dichiarando User , MyMessageBox può ancora formare un puntatore o 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* dataMessageList; }; class User { public: // also ok, since it's now defined MyMessageBox dataMsgBox; }; 

Non è ansible farlo viceversa: come già detto, un membro della class deve avere una definizione. (La ragione è che il compilatore ha bisogno di sapere quanta memoria occupa l’ User 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, dal momento che non conosce ancora la dimensione.


Una nota a margine, questa funzione:

  void sendMessage(Message *msg, User *recvr); 

Probabilmente non dovresti prendere nessuno di questi con il puntatore. Non è ansible inviare un messaggio senza un messaggio, né si può inviare un messaggio senza un utente per inviarlo a. E entrambe queste situazioni sono espresse passando null come argomento ad entrambi i parametri (null è un valore puntatore perfettamente valido!)

Piuttosto, usa un riferimento (possibilmente const):

  void sendMessage(const Message& msg, User& recvr); 
  1. Inoltra dichiara Utente
  2. Metti la dichiarazione di MyMessageBox prima dell’Utente

I compilatori C ++ elaborano i loro input una sola volta. Ogni class che usi deve essere stata definita per prima. Si utilizza MyMessageBox prima di definirlo. In questo caso, puoi semplicemente scambiare le due definizioni di class.

È necessario definire MyMessageBox prima di User – perché l’utente include l’object di MyMessageBox in base al valore (e quindi il compilatore dovrebbe conoscere le sue dimensioni).

Inoltre dovrai inoltrare dichiarare User befor MyMessageBox – perché MyMessageBox include un membro di tipo User *.

Su una nota correlata, se avessi:

  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; }; 

Quindi funzionerebbe anche, perché l’utente è definito in MyMessageBox come puntatore

È necessario dichiarare il prototipo prima di utilizzarlo:

 class User; class MyMessageBox { public: void sendMessage(Message *msg, User *recvr); Message receiveMessage(); vector *dataMessageList; }; class User { public: MyMessageBox dataMsgBox; }; 

modifica : scambiati i tipi

È sempre consigliato in C ++ che tu abbia una class per file di intestazione, vedi questa discussione in SO [ 1 ]. La risposta di GManNickG dice perché questo accada. Ma il modo migliore per risolvere questo è mettere la class User in un file di intestazione ( User.h ) e nella class MyMessageBox in un altro file di intestazione ( MyMessageBox.h ). Quindi nel tuo User.h includi MyMessageBox.h e in MyMessageBox.h tu includi User.h . Non dimenticare “include gaurds” [ 2 ] in modo che il tuo codice venga compilato correttamente.