C 中前置宣告的應用與陷阱

2021-09-29 11:44:18 字數 3449 閱讀 5496

有一定c++開發經驗的朋友可能會遇到這樣的場景:兩個類a與b是強耦合關係,類a要引用b的物件,類b也要引用類a的物件。好的,不難,我的第一直覺讓我寫出這樣的**:

// a.h #include "b.h" class a ;

#include 「a.h」

a::a(void)

a::~a(void)

// b.h

#include 「a.h」

class b

;// b.cpp

#include 「b.h」

b::b(void)

b::~b(void)

好的,完成,編譯一下a.cpp,不通過。再編譯b.cpp,還是不通過。編譯器都被搞暈了,編譯器去編譯a.h,發現包含了b.h,就去編譯b.h。編譯b.h的時候發現包含了a.h,但是a.h已經編譯過了(其實沒有編譯完成,可能編譯器做了記錄,a.h已經被編譯了,這樣可以避免陷入死迴圈。編譯出錯總比死迴圈強點),就沒有再次編譯a.h就繼續編譯。後面發現用到了a的定義,這下好了,a的定義並沒有編譯完成,所以找不到a的定義,就編譯出錯了。提示資訊如下:

1>d:/vs2010/test/test/a.h(5): error c2146: syntax error : missing ';' before identifier 'b'

1>d:/vs2010/test/test/a.h(5): error c4430: missing type specifier - int assumed. note: c++ does not support default-int

1>d:/vs2010/test/test/a.h(5): error c4430: missing type specifier - int assumed. note: c++ does not support default-int

那怎麼辦?有辦法,c++為我們提供了前置宣告。前置宣告是什麼?舉個形象點的例子,就是我要蓋乙個屋子(chouse),光有屋子還不行啊,我還得有床(cbed)。但是屋子還沒蓋好,總不能先買床吧,床的大小我定了,改天買。先得把房子蓋好,蓋房子的時候我先給床留個位置,等房子蓋好了,我再決定買什麼樣的床。前置宣告就是我在宣告乙個類(chouse)的時候,用到了另外乙個類的定義(cbed),但是cbed還沒有定義呢,而且我還先不需要cbed的定義,只要知道cbed是乙個類就夠了。那好,我就先宣告類cbed,告訴編譯器cbed是乙個類(不用包含cbed的標頭檔案):

class cbed;

然後在chouse中用到cbed的,都用cbed的指標型別代(因為指標型別固定大小的,但是cbed的大小只用知道了cbed定義才能確定)。等到要實現chouse定義的時候,就必須要知道cbed的定義了,那是再包好cbed的標頭檔案就行了。

前置宣告有時候很有用,比如說兩個類相互依賴的時候要。還有前置宣告可以減少標頭檔案的包含層次,減少出錯可能。上面說的例子。

// house.h class cbed; // 蓋房子時:現在先不買,肯定要買床的 class chouse ;

// house.cpp

#include 「bed.h」

#include 「house.h」 // 等房子開始裝修了,要買床了

chouse::chouse(void)

chouse::~chouse(void)

void chouse::gotobed()

// bed.h

class cbed

;// bed.cpp

#include 「bed.h」

cbed::cbed(void)

cbed::~cbed(void)

void cbed::sleep()

; // house.cpp

#include 「bed.h」

#include 「house.h」 // 等房子開始裝修了,要買床了

chouse::chouse(void)

bed(

new cbed())

chouse::chouse(cbed& bedtmp)

bed(bedtmp)

chouse::~chouse(void)

void chouse::gotobed()

2、不能在chouse的宣告中使用cbed的方法

使用了未定義的型別cbed;

bed->sleep的左邊必須指向類/結構/聯合/泛型型別

class cbed; // 蓋房子時:現在先不買,肯定要買床的 class chouse };

3、在cbed定義之前呼叫cbed的析構函式

// house.h class cbed; // 蓋房子時:現在先不買,肯定要買床的 class chouse };

// house.cpp

#include 「bed.h」

#include 「house.h」 // 等房子開始裝修了,要買床了

chouse::chouse(void)

chouse::~chouse(void)

void chouse::gotobed()

// bed.h

class cbed

;// bed.cpp

#include 「bed.h」

cbed::cbed(void)

cbed::~cbed(void)

void cbed::sleep()

接下來,給出開篇第乙個問題的答案:

// a.h class b; class a ;

#include 「b.h」

#include 「a.h」

a::a(void)

a::~a(void)

// b.h

class a;

class b

;// b.cpp

#include 「a.h」

#include 「b.h」

b::b(void)

b::~b(void)

《c++ primer 4edition》在類的友元一章節中說到,如果在乙個類a的宣告中將另乙個類b的成員函式宣告為友元函式f,那麼類a必須事先知道類b的定義;類b的成員函式f宣告如果使用類a作為形參,那麼也必須知道類a的定義,那麼兩個類就互相依賴了。要解決這個問題必須使用類的前置宣告。例如:

// house.h #include "bed.h" class chouse };

// house.cpp

#include 「house.h」

chouse::chouse(void)

chouse::~chouse(void)

void chouse::gotobed()

// bed.h

class chouse;

class cbed

;// bed.cpp

#include 「house.h」

cbed::cbed(void)

cbed::~cbed(void)

void cbed::sleep(chouse& h)

;

C 中前置宣告的應用與陷阱

有一定c 開發經驗的朋友可能會遇到這樣的場景 兩個類a與b是強耦合關係,類a要引用b的物件,類b也要引用類a的物件。好的,不難,我的第一直覺讓我寫出這樣的 a.h include b.h classa include a.h a a void a a void b.h include a.h cla...

C 中前置宣告

有一定c 開發經驗的朋友可能會遇到這樣的場景 兩個類a與b是強耦合關係,類a要引用b的物件,類b也要引用類a的物件。好的,不難,我的第一直覺讓我寫出這樣的 a.h include b.h class a include a.h a a void a a void b.h include a.h cl...

關於C 中的前置宣告

關於c 中的前置宣告 在編寫c 程式的時候,偶爾需要用到前置宣告 forward declaration 下面的程式中,帶注釋的那行就是類b的前置說明。這是必須的,因為類a中用到了類b,而類b的宣告出現在類a的後面。如果沒有類b的前置說明,下面的程式將不同通過編譯,編譯器將會給出類似 缺少型別說明符...