Khi trình biên dịch biên dịch lớp User
và đến MyMessageBox
dòng, MyMessageBox
vẫn chưa được xác định. Trình biên dịch không có ý tưởng MyMessageBox
tồ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 MyMessageBox
nó đã đượ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 MyMessageBox
tên User
sẽ 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
, MyMessageBox
vẫ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ớ User
chiế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);