C ++での「Xは型に名前を付けません」エラー


123

以下のように宣言した2つのクラスがあります。

class User
{
public:
  MyMessageBox dataMsgBox;
};

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

gccを使用してコンパイルしようとすると、次のエラーが発生します。

MyMessageBoxがタイプに名前を付けていません


16
IDEによって生成されたインポートガードが重複していることを理解するために、このエラーに終わりはありません
Mazyod

1
.cpp内の.h / .hppインクルードの後に​​実際の宣言がある場合でも、クラスが定義される前に.h / .hppファイルの宣言へのextern参照を配置した場合にも、このエラーが発生する可能性があることに注意してください。ファイル。
フクロウ

また、コマンドg++ではなく、常にC ++ファイルをコンパイルする必要がありますgcc
Lorenzo Battilocchi

回答:


203

コンパイラがクラスUserをコンパイルしてMyMessageBox行に到達するとき、MyMessageBoxまだ定義されていません。コンパイラはMyMessageBox存在しないため、クラスメンバーの意味を理解できません。

メンバーとして使用する前に、MyMessageBoxが定義されていることを確認する必要があります。これは、定義の順序を逆にすることで解決されます。ただし、循環依存関係があります。上に移動すると、名前の定義では定義されません。MyMessageBoxUserMyMessageBoxUser

あなたができることは、前方宣言 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);

おそらくそれらのいずれかをポインタで受け取るべきではありません。メッセージなしでメッセージを送信することはできません。また、送信先のユーザーなしでメッセージを送信することもできません。そして、これらの状況はどちらも、どちらかのパラメーターの引数としてnullを渡すことで表現できます(nullは完全に有効なポインター値です!)

むしろ、参照(おそらくconst)を使用します。

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

3
+1今日は何かを学びました-私は前向きに宣言MyMessageBoxすれば十分だと思いました。MyMessageBoxタイプの変数もある場合はどうUserなるでしょうか?それはデッドロックでしょうか?
Amarghosh 2010年

14
@Amargosh:はい、それは不可能でしょう。以来、論理的に不可能なだけでなくUser必要がありますMessageBox持っていることになるのUserだろうこれ、MessageBox持っていることになるのUserだろうこれ、MessageBox持っていることになるのUserだろうこれ、MessageBox持っていると思われるがUser...
GManNickG


3

C ++コンパイラは入力を1回処理します。使用する各クラスを最初に定義しておく必要があります。MyMessageBox定義する前に使用します。この場合、2つのクラス定義を単純に入れ替えることができます。


機能しませんスワッピングMyMessageBoxありUser、それのメソッド宣言のタイプを。
Amarghosh 2010年

実際、その定義ではclassを使用していませんUser。重要な違いです。これは、Userクラスはその時点で宣言するだけでよく、定義する必要がないためです。しかし、GManの広範な投稿を参照してください。
MSalters 2010年

ええ、でもUser型がまだ宣言されていないので、単に定義を交換するだけでは機能しません。
Amarghosh 2010年

3

MyMessageBoxは、ユーザーの前に定義する必要があります。ユーザーは、値によって MyMessageBoxのオブジェクトを含めるためです(したがって、コンパイラはそのサイズを知っている必要があります)。

MyMessageBoxにはUser *タイプのメンバーが含まれているため、MyMessageBoxの前に User を転送宣言する必要もあります。


3

関連するノートでは、あなたが持っていた場合:

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

次に、UserがMyMessageBoxでポインタとして定義されているため、これも機能します。


1
前方宣言が用語
beniv '13 / 07/13

1

使用する前に、プロトタイプを宣言する必要があります。

class User;

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

class User
{
public:
 MyMessageBox dataMsgBox;
};

編集:タイプを入れ替え


1
いいえ、機能しません。クラスメンバーを定義する必要があります。宣言はできません。
MSalters 2010年

1

C ++では、ヘッダーファイルごとに1つのクラスがあることが常に推奨されます。SO[ 1 ]のこの説明を参照してください。GManNickGの回答は、これがなぜ起こるかを示しています。ただし、これを解決する最善の方法は、Userクラスを1つのヘッダーファイル(User.h)に配置し、MyMessageBoxクラスを別のヘッダーファイル(MyMessageBox.h)に配置することです。次に、あなたの中にあなたUser.hを含めMyMessageBox.hMyMessageBox.hあなたの中に含めますUser.h。コードが正常にコンパイルされるように、「include gaurds」[ 2 ]を忘れないでください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.