Ketika kompilator mengkompilasi kelas User
dan sampai ke MyMessageBox
baris, MyMessageBox
belum ditentukan. Kompilator tidak memiliki ide MyMessageBox
, jadi tidak dapat memahami arti dari anggota kelas Anda.
Anda perlu memastikan MyMessageBox
sudah ditentukan sebelum Anda menggunakannya sebagai anggota. Ini diselesaikan dengan membalik urutan definisi. Namun, Anda memiliki ketergantungan siklik: jika Anda pindah ke MyMessageBox
atas User
, maka definisi MyMessageBox
namanya User
tidak akan ditentukan!
Apa yang dapat Anda lakukan adalah menyatakan ke depan User
; yaitu, nyatakan tetapi jangan definisikan. Selama kompilasi, tipe yang dideklarasikan tetapi tidak ditentukan disebut tipe tidak lengkap . Pertimbangkan contoh yang lebih sederhana:
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;
}
Dengan mendeklarasikan terus User
, MyMessageBox
masih bisa membentuk sebuah pointer atau referensi ke sana:
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;
};
Anda tidak dapat melakukan ini sebaliknya: seperti yang disebutkan, seorang anggota kelas perlu memiliki definisi. (Alasannya adalah bahwa kompilator perlu mengetahui berapa banyak memori yang digunakan User
, dan mengetahui bahwa ia perlu mengetahui ukuran anggotanya.) Jika Anda mengatakan:
class MyMessageBox;
class User
{
public:
// size not available! it's an incomplete type
MyMessageBox dataMsgBox;
};
Itu tidak akan berhasil, karena belum tahu ukurannya.
Di samping catatan, fungsi ini:
void sendMessage(Message *msg, User *recvr);
Mungkin tidak boleh mengambil salah satu dari mereka dengan penunjuk. Anda tidak dapat mengirim pesan tanpa pesan, Anda juga tidak dapat mengirim pesan tanpa pengguna untuk mengirimkannya. Dan kedua situasi tersebut dapat diekspresikan dengan meneruskan null sebagai argumen ke salah satu parameter (null adalah nilai penunjuk yang benar-benar valid!)
Sebaliknya, gunakan referensi (mungkin const):
void sendMessage(const Message& msg, User& recvr);