Khi trình biên dịch biên dịch lớp Uservà đến MyMessageBoxdòng, MyMessageBoxvẫn chưa được xác định. Trình biên dịch không có ý tưởng MyMessageBoxtồn tại, vì vậy không thể hiểu ý nghĩa của thành viên lớp của bạn.
Bạn cần đảm bảo rằng MyMessageBoxnó đã được xác định trước khi bạn sử dụng nó như một thành viên. Điều này được giải quyết bằng cách đảo ngược thứ tự định nghĩa. Tuy nhiên, bạn có phụ thuộc theo chu kỳ: nếu bạn di chuyển MyMessageBoxở trên User, thì trong định nghĩa MyMessageBoxtên Usersẽ không được xác định!
Những gì bạn có thể làm là khai báo chuyển tiếp User ; nghĩa là khai báo nó nhưng không định nghĩa nó. Trong quá trình biên dịch, một kiểu được khai báo nhưng không được định nghĩa được gọi là kiểu không hoàn chỉnh . Hãy xem xét ví dụ đơn giản hơn:
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;
}
Bằng cách khai báo chuyển tiếp User, MyMessageBoxvẫn có thể tạo thành một con trỏ hoặc tham chiếu đến nó:
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;
};
Bạn không thể làm điều này theo cách khác: như đã đề cập, một thành viên trong lớp cần phải có một định nghĩa. (Lý do là trình biên dịch cần biết dung lượng bộ nhớ Userchiếm bao nhiêu và biết rằng nó cần biết kích thước của các thành viên của nó.) Nếu bạn muốn nói:
class MyMessageBox;
class User
{
public:
// size not available! it's an incomplete type
MyMessageBox dataMsgBox;
};
Nó sẽ không hoạt động, vì nó chưa biết kích thước.
Một lưu ý nhỏ, chức năng này:
void sendMessage(Message *msg, User *recvr);
Có lẽ không nên lấy một trong hai cái đó bằng con trỏ. Bạn không thể gửi tin nhắn mà không có tin nhắn, cũng như không thể gửi tin nhắn mà không có người dùng để gửi. Và cả hai trường hợp đó đều có thể diễn đạt được bằng cách chuyển null làm đối số cho một trong hai tham số (null là một giá trị con trỏ hoàn toàn hợp lệ!)
Thay vào đó, hãy sử dụng một tham chiếu (có thể là const):
void sendMessage(const Message& msg, User& recvr);