2010-01-25 16 views
86

Ich habe zwei, wie unten angegebenen Klassen:„nennt keinen Typen“ Fehler

class User 
{ 
public: 
    MyMessageBox dataMsgBox; 
}; 

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

Wenn ich versuche, es mit gcc kompilieren, gibt es die folgenden Fehler:

MyMessageBox does not name a type

+10

Die endlosen Zeiten gehe ich diesen Fehler, nur um zu erkennen, dass die Import-Wachen von der IDE verdoppelt werden – Mazyod

+0

Beachten Sie, dass Sie auch diesen Fehler erhalten können, wenn Sie einen externen Verweis auf eine Deklaration in einer .h/.hpp-Datei platzieren bevor die Klasse definiert wird, auch wenn Sie die tatsächliche Deklaration nach der Aufnahme von .h/.hpp in der .cpp-Datei haben. – Owl

+0

@Mazyod. Danke Danke. Ich konnte nicht herausfinden, was zum Teufel diesen seltsamen Fehler verursacht hat. –

Antwort

160

Wenn die Compiler kompiliert die Klasse User und gelangt in die MyMessageBox Zeile, MyMessageBox ist noch nicht definiert. Der Compiler hat keine Idee MyMessageBox existiert, so kann die Bedeutung Ihres Klassenmitglieds nicht verstehen.

Sie müssen sicherstellen, MyMessageBox ist definiert vor Sie verwenden es als Mitglied. Dies wird durch Umkehrung der Definitionsreihenfolge gelöst. Sie haben jedoch eine zyklische Abhängigkeit: Wenn Sie MyMessageBox über User verschieben, wird in der Definition von MyMessageBox der Name User nicht definiert werden!

Was Sie tun können, ist forward declareUser; das heißt, deklarieren Sie es, aber definieren Sie es nicht. Ein Typ, der deklariert, aber nicht definiert ist, wird während der Kompilierung als unvollständiger Typ bezeichnet. das einfacheres Beispiel vor:

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

Durch vorwärts User deklarieren, können MyMessageBox noch einen Zeiger oder Verweis auf sie bilden:

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

Sie nicht diese in die andere Richtung tun um: wie erwähnt, Ein Klassenmitglied muss eine Definition haben. (Der Grund dafür ist, dass der Compiler muss wissen, wie viel Speicher User in Anspruch nimmt, und wissen, dass sie die Größe ihrer Mitglieder wissen muss.) Wenn Sie sagen würden:

class MyMessageBox; 

class User 
{ 
public: 
    // size not available! it's an incomplete type 
    MyMessageBox dataMsgBox; 
}; 

würde es nicht funktionieren , da es die Größe noch nicht kennt.


Auf einer Seite zur Kenntnis, diese Funktion:

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

wahrscheinlich auch nicht von denen, durch Zeiger nehmen soll. Sie können keine Nachricht ohne Nachricht senden oder eine Nachricht senden, ohne dass ein Benutzer sie senden muss. Und diese beiden Situationen sind ausdrückbar durch zu null als Argument übergeben entweder Parameter

vielmehr eine Referenz (möglicherweise const) (null ein absolut gültige Zeigerwert ist!):

void sendMessage(const Message& msg, User& recvr); 
+1

+1 Habe heute etwas gelernt - ich dachte mir, 'MyMessageBox' würde reichen. Was wäre, wenn "MyMessageBox" auch eine Variable vom Typ "User" hätte - wäre das ein Deadlock? – Amarghosh

+9

@Amargosh: Ja, es wäre unmöglich. Logisch auch unmöglich, da "User" eine "MessageBox" hätte, die einen 'User' hätte, der eine' MessageBox' hätte, die einen 'User' hätte, der eine' MessageBox' hätte, die ein '' hätte User', der eine 'MessageBox' hätte, die einen 'User' hätte ... – GManNickG

+0

Danke GMan. Ich habe Änderungen an meinem Code vorgenommen, wie Sie es vorgeschlagen haben, und es funktioniert jetzt einwandfrei. –

0

Sie müssen erklären der Prototyp es vor dem Gebrauch:

class User; 

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

class User 
{ 
public: 
MyMessageBox dataMsgBox; 
}; 

bearbeiten: Swapped die Typen

+1

Nein, wird nicht funktionieren. Klassenmitglieder müssen definiert und nicht forward deklariert werden. – MSalters

2

C++ Compiler verarbeiten die ir Eingabe einmal. Jede Klasse, die Sie verwenden, muss zuerst definiert worden sein. Sie verwenden MyMessageBox, bevor Sie es definieren. In diesem Fall können Sie einfach die beiden Klassendefinitionen austauschen.

+0

Swapping funktioniert nicht, da 'MyMessageBox' den' User'-Typ in seiner Methodendeklaration hat. – Amarghosh

+0

Funktioniert nicht, weil MyMessageBox auch die Benutzerklasse verwendet. –

+0

Tatsächlich verwendet diese Definition nicht _use_ class 'User'. Wichtiger Unterschied, denn das bedeutet, dass die Klasse Benutzer zu diesem Zeitpunkt nur _declared_ sein muss, nicht _defined_. Aber siehe GMans umfangreichen Beitrag. – MSalters

6
  1. nach vorne erklären Benutzer
  2. Setzen Sie die Deklaration von MyMessageBox vor User
2

Sie müssen MyMessageBox vor Benutzer definieren - weil Benutzerobjekt von MyMessageBox von Wert sind (und so sollte Compiler wissen seine Größe).

Auch müssen Sie forward deklarieren Benutzer vor MyMessageBox - weil MyMessageBox Mitglied von User * Typ enthalten.

2

Über einen entsprechenden Hinweis, wenn Sie hatte:

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

, dass dann auch in MyMessageBox definiert als ein Zeiger ist, weil der Benutzer

+0

Forward-Deklaration ist der Begriff – benziv

0

Es wird immer in C++ ermutigt funktionieren würde, dass Sie eine haben Klasse pro Header-Datei, siehe diese Diskussion in SO [1]. GManNickG antwortet, warum dies geschieht. Aber der beste Weg, dies zu lösen, ist User Klasse in eine Header-Datei (User.h) und MyMessageBox Klasse in eine andere Header-Datei (MyMessageBox.h) setzen. Dann schließen Sie in Ihrer User.hMyMessageBox.h und in MyMessageBox.h Sie User.h ein. Vergiss nicht "include gaurds" [2], damit dein Code erfolgreich kompiliert werden kann.