有一定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"
classb;
#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
" //注:這個很關鍵在原始檔cpp處是要增加標頭檔案的#include
"house.h"//
等房子開始裝修了,要買床了
chouse::chouse(
void
)chouse::~chouse(void
)void
chouse::gotobed()
class
cbed;//
bed.cpp
#include "
bed.h
"cbed::cbed(
void
)cbed::~cbed(void
)void
cbed::sleep()
注意這裡有陷阱:
1、cbed* bed;必須用指標或引用
引用版本:
//house.h
class cbed; //
蓋房子時:現在先不買,肯定要買床的
class
chouse;//
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的方法,但是可以在原始檔中chouse.cpp中使用,因為有#include "bed.h"
使用了未定義的型別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()
class
cbed;//
bed.cpp
#include "
bed.h
"cbed::cbed(
void
)cbed::~cbed(void
)void
cbed::sleep()
#include "
house.h
"int
main()
接下來,給出開篇第乙個問題的答案:
//a.hclass
b;classa;
#include "
b.h"
#include
"a.h
"a::a(
void
)a::~a(void)//
b.hclass
a;classb;
#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()
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 class a include a.h a a void a a void b.h include a.h cl...
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的前置說明,下面的程式將不同通過編譯,編譯器將會給出類似 缺少型別說明符...