1. ホーム
  2. c++

[解決済み] C++で "X does not name a type "エラー

2022-03-01 16:21:22

質問

以下のような2つのクラスが宣言されています。

class User
{
public:
  MyMessageBox dataMsgBox;
};

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

gccでコンパイルしようとすると、以下のようなエラーが出ます。

MyMessageBoxに型名がありません。

解決方法は?

コンパイラがクラスをコンパイルするとき 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;
}

を前方に宣言することで 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;
};

あなた できない 前述のように、クラスのメンバには定義が必要です。(その理由は、コンパイラがどの程度のメモリ User が占有し、それを知るためには、そのメンバーのサイズを知る必要がある)。もし、あなたが

class MyMessageBox;

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

まだサイズを知らないので、うまくいかないでしょう。


余談ですが、この機能。

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

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

そうではなく、参照(場合によってはconst)を使用します。

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