2010-01-25 237 views
86

我必須聲明,如下兩類:「沒有指定類型」的錯誤

class User 
{ 
public: 
    MyMessageBox dataMsgBox; 
}; 

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

當我嘗試編譯使用gcc,它提供了以下錯誤:

MyMessageBox does not name a type

+10

無盡的時間,我去這個錯誤,只是意識到由IDE生成的導入警衛重複 – Mazyod 2015-08-15 11:39:22

+0

請注意,如果您將一個外部引用聲明放在.h/.hpp文件中也可以得到此錯誤在定義類之前,即使在.cpp文件中的.h/.hpp包含之後有實際的聲明。 – Owl 2016-03-19 20:01:41

+0

@Mazyod。謝謝謝謝。我無法弄清楚是什麼造成了這個奇怪的錯誤。 – 2017-02-10 19:13:04

回答

160

當編譯器編譯類User並進入MyMessageBox行,MyMessageBox尚未定義。編譯器不知道MyMessageBox存在,所以不能理解你的類成員的含義。

您需要確保MyMessageBox被定義爲之前您使用它作爲成員。這是通過顛倒定義順序來解決的。但是,您具有循環依賴關係:如果將MyMessageBox移動到User以上,則在MyMessageBox的定義中將不會定義名稱User

您可以做的是正向聲明User;即聲明它,但不要定義它。在編譯過程中,聲明但未定義的類型稱爲不完整類型。 考慮簡單的例子:

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

向前聲明UserMyMessageBox仍然可以形成一個指針或引用它:

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

無法做到這一點的其他方式:如前所述,一個班級成員需要有一個定義。 (原因是編譯器需要知道多少內存User如何佔用了,要知道,它需要知道其成員的大小。)如果你是在說:

class MyMessageBox; 

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

這是行不通的,因爲它還不知道尺寸。


在一個側面說明,這樣的功能:

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

也許不應該由指針採取這類原因。沒有消息就不能發送消息,也不能發送沒有用戶發送消息的消息。而這兩方面的情況是由空作爲參數傳遞給任一參數表達

相反,使用引用(可能是const的)(null是一個完全有效的指針值!):

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

+1今天學到了一些東西 - 我認爲向前聲明MyMessageBox就足夠了。如果'MyMessageBox'也有一個'User'類型的變量 - 那會是一個死鎖嗎? – Amarghosh 2010-01-25 15:38:57

+9

@Amargosh:是的,這是不可能的。在邏輯上也是不可能的,因爲'User'會有一個'MessageBox',它有一個'User',它有一個'MessageBox',它有一個'User',它有一個'MessageBox',用戶',這將有一個'MessageBox'這將有一個'用戶'... – GManNickG 2010-01-25 15:41:36

+0

謝謝GMAN。我已經按照你的建議對我的代碼進行了修改,現在它工作的很好。 – 2010-01-26 12:09:46

0

你必須申報使用前原型它:

class User; 

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

class User 
{ 
public: 
MyMessageBox dataMsgBox; 
}; 

編輯:交換了類型

+1

不,不會工作。班級成員必須定義,而不是被宣佈。 – MSalters 2010-01-25 15:27:56

2

C++編譯器處理所述ir輸入一次。您使用的每個課程都必須先定義。您在定義它之前使用MyMessageBox。在這種情況下,您可以簡單地交換兩個類的定義。

+0

由於'MyMessageBox'在其方法聲明中有'User'類型,交換將不起作用。 – Amarghosh 2010-01-25 15:33:56

+0

不工作,因爲MyMessageBox也使用User類。 – 2010-01-25 15:39:24

+0

實際上,那個定義並沒有_use_ class'User'。重要的區別,因爲這意味着類用戶只需在該點_declared_,而不是_defined_。但請參閱GMan廣泛的帖子。 – MSalters 2010-01-26 08:46:12

6
  1. 正向聲明用戶
  2. 將MyMessageBox的聲明之前用戶
2

您需要用戶之前定義MyMessageBox - 因爲用戶包括MyMessageBox 的對象由值(所以編譯器應該知道它的大小)。

您還需要正向聲明用戶befor MyMessageBox - 因爲MyMessageBox包含User *類型的成員。

2

與此相關的,如果你有:

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

那麼這也將工作,因爲用戶在MyMessageBox定義爲指針

+0

前向聲明是該術語 – benziv 2017-07-13 01:14:11

0

它在C++中,你有一個總是鼓勵每個頭文件的類,參見SO [1]中的討論。 GManNickG答案說明了爲什麼會發生這種情況。但解決此問題的最佳方法是將User類放在另一個頭文件(MyMessageBox.h)中的一個頭文件(User.h)和MyMessageBox類中。然後在您的User.h中包含MyMessageBox.h,並在MyMessageBox.h中包含User.h。不要忘記「包括gaurds」[2],以便您的代碼編譯成功。