web-dev-qa-db-ja.com

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

次のように宣言された2つのクラスがあります。

class User
{
public:
  MyMessageBox dataMsgBox;
};

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

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

MyMessageBoxはタイプに名前を付けません

107
Rakesh K

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

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

できることはforward declareUser;つまり、宣言するが定義しないでください。コンパイル中、宣言されているが定義されていない型は、不完全型と呼ばれます。より単純な例を考えてみましょう。

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

Userを前方宣言することにより、MyMessageBoxは引き続きポインターまたは参照を形成できます。

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

あなたはcannotこれを別の方法で行います:前述のように、クラスメンバには定義が必要です。 (理由は、コンパイラーが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);
186
GManNickG
  1. 前方宣言ユーザー
  2. MyMessageBoxの宣言をユーザーの前に置きます
8
Brian R. Bondy

関連するメモで、次の場合:

    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でポインターとして定義されているため、それも機能します

2
awesomeamyg

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

2
MSalters

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

また、MyMessageBoxの前にforward declareUserが必要です。これは、MyMessageBoxにUser *タイプのメンバーが含まれているためです。

2

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

class User;

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

class User
{
public:
 MyMessageBox dataMsgBox;
};

編集:タイプを交換しました

0
Alex LE

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

0
Chehadeh