コンパイラがクラス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);
おそらくそれらのいずれかをポインタで受け取るべきではありません。メッセージなしでメッセージを送信することはできません。また、送信先のユーザーなしでメッセージを送信することもできません。そして、これらの状況はどちらも、どちらかのパラメーターの引数としてnullを渡すことで表現できます(nullは完全に有効なポインター値です!)
むしろ、参照(おそらくconst)を使用します。
void sendMessage(const Message& msg, User& recvr);