Cách nghĩ về điều này là "nghĩ như một trình biên dịch".
Hãy tưởng tượng bạn đang viết một trình biên dịch. Và bạn thấy mã như thế này.
// file: A.h
class A {
B _b;
};
// file: B.h
class B {
A _a;
};
// file main.cc
#include "A.h"
#include "B.h"
int main(...) {
A a;
}
Khi bạn đang biên dịch tệp .cc (hãy nhớ rằng .cc chứ không phải .h là đơn vị biên dịch), bạn cần phân bổ không gian cho đối tượng A
. Vì vậy, tốt, bao nhiêu không gian sau đó? Đủ để lưu trữ B
! Kích thước của B
nó là bao nhiêu? Đủ để lưu trữ A
! Giáo sư.
Rõ ràng một tài liệu tham khảo tròn mà bạn phải phá vỡ.
Bạn có thể phá vỡ nó bằng cách cho phép trình biên dịch thay thế dự trữ nhiều không gian như nó biết về trả trước - ví dụ, con trỏ và tham chiếu, sẽ luôn là 32 hoặc 64 bit (tùy thuộc vào kiến trúc) và vì vậy nếu bạn thay thế (một trong hai) một con trỏ hoặc tài liệu tham khảo, mọi thứ sẽ rất tuyệt Hãy nói rằng chúng tôi thay thế trong A
:
// file: A.h
class A {
// both these are fine, so are various const versions of the same.
B& _b_ref;
B* _b_ptr;
};
Bây giờ mọi thứ đã tốt hơn. Một chút nào đó. main()
vẫn nói:
// file: main.cc
#include "A.h" // <-- Houston, we have a problem
#include
, cho tất cả các phạm vi và mục đích (nếu bạn lấy bộ tiền xử lý ra) chỉ cần sao chép tệp vào .cc . Vì vậy, thực sự, .cc trông giống như:
// file: partially_pre_processed_main.cc
class A {
B& _b_ref;
B* _b_ptr;
};
#include "B.h"
int main (...) {
A a;
}
Bạn có thể thấy lý do tại sao trình biên dịch không thể giải quyết vấn đề này - nó không biết nó B
là gì - nó thậm chí chưa bao giờ nhìn thấy biểu tượng trước đó.
Vì vậy, hãy nói với trình biên dịch về B
. Điều này được gọi là một tuyên bố chuyển tiếp , và được thảo luận thêm trong câu trả lời này .
// main.cc
class B;
#include "A.h"
#include "B.h"
int main (...) {
A a;
}
Điều này hoạt động . Nó không tuyệt lắm . Nhưng tại thời điểm này, bạn nên hiểu rõ về vấn đề tham chiếu vòng tròn và những gì chúng tôi đã làm để "khắc phục" nó, mặc dù cách khắc phục là không tốt.
Lý do sửa lỗi này là xấu bởi vì người tiếp theo #include "A.h"
sẽ phải khai báo B
trước khi họ có thể sử dụng nó và sẽ nhận được một #include
lỗi khủng khiếp . Vì vậy, hãy chuyển bản khai vào chính Ah .
// file: A.h
class B;
class A {
B* _b; // or any of the other variants.
};
Và trong Bh , tại thời điểm này, bạn có thể chỉ cần #include "A.h"
trực tiếp.
// file: B.h
#include "A.h"
class B {
// note that this is cool because the compiler knows by this time
// how much space A will need.
A _a;
}
HTH.