เมื่อคอมไพเลอร์คอมไพเลอร์คลาส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);