在 C++ 開發中,當類別 A 需要包含類別 B 的實例,而類別 B 同時也需要包含類別 A 的實例時,若直接在頭文件中雙向 #include,會導致編譯器陷入無限遞迴的「死循環」,無法完成編譯。
// A.h
#include "B.h"
class A {
int i;
B b; // 直接包含 B 實例
};
// B.h
#include "A.h"
class B {
int i;
A a; // 直接包含 A 實例
};
這種寫法會導致編譯器在解析 A.h 時載入 B.h,B.h 又載入 A.h,形成無限循環。
核心原則:頭文件中僅前向宣告類別,改用指標或引用持有對象,實例化邏輯移至實作文件。
class B; 前向宣告。B* ptrB;。前向宣告僅允許宣告指標/引用,不可直接實例化對象(因為編譯器不知道 B 的大小)。A objA;。// A.h
#include <iostream>
using namespace std;
class B; // 前向宣告
class A {
public:
B* ptrB; // 僅能用指標/引用
void showA() { cout << "Class A" << endl; }
};
// B.h
#include <iostream>
#include "A.h"
using namespace std;
class B {
public:
A objA; // 可直接實例化
void showB() { cout << "Class B" << endl; }
};
// main.cpp
#include "B.h"
int main() {
B b;
b.showB();
b.objA.showA();
return 0;
}
class B;)讓編譯器知道類別存在,但不知道大小,故只能用指標/引用。