下面主要介紹了前向聲明概念、用法以及和#include區別
前向聲明概念(forward declaration)
在程序中引入了類類型的B.在聲明之后,定義之前,類B是一個不完全類型(incompete type),即已知B是一個類型,但不知道包含哪些成員.不完全類型只能以有限方式使用,不能定義該類型的對象,不完全類型只能用於定義指向該類型的指針及引用,或者用於聲明(而不是定義)使用該類型作為形參類型或返回類型的函數.
前向聲明應用場景
當你需要定義兩個類或者結構,例如A和B,而這兩個類需要互相引用,這時候在定義A的時候,B還沒有定義,那怎么引用它呢,這時候就需要前向聲明(forward declaration)了,前向聲明格式如下: class B;當你在定義類A之前聲明了B,那么就會在程序中引入了類類型的B,編譯器知道你會在后面的某個地方定義類B,所以允許你在類A中引用類B。但是,在聲明之后,定義之前,類B是一個不完全類型(incompete type),即已知B是一個類型,但不知道這個類型的一些性質(比如包含哪些成員和操作)。
前向聲明的使用限制:(就拿上面聲明B類說明)
1.不恩能夠定義B類的對象;
2.可以用於定義只想這個類型的指針或者引用;
3.用於聲明使用該類型作為形參或者返回類型的函數;
除了上面的限制,我們可以用它做些什么事情嗎?
在C++中,如果要編寫一個新類的頭文件,一般是要#include一堆依賴的頭文件,但利用前向聲明和c++編譯器的特性,可以減少這里的工作量。
因為c++編譯器做的事情主要是:1.掃描符號;2.確定對象大小。利用這個特性,當我們編寫一個新類的頭文件時,就可以用前向聲明,減少大量的#include,減少編譯的
工作量。
例如:
1.B類用到A類,操作如下,就不需要加A.h了,減少編譯工作量
1:
2: //B.h
3: class A;//調用類A,前向聲明
4: class
5: B
6: {
7: private:
8: A *a; //聲明指針
9: };
2.在聲明成員函數的形參或者返回類型時,也可以用前向聲明
即使我們沒有定義一個foo類,也可以用,因為成員函數不占類對象的大小,編譯器可以確定對象大小,前向聲明的作用在於告訴編譯器這個一個在別的地方定義的類型。這樣編譯器就能生成正確的符號表了。
1:
2: //Sample.h
3: class foo;
4: class
5: Sample
6: {
7: private:
8: foo foo_test(foo &);
9: };
常犯錯誤:
1:
2: #ifndef RESOURCE_H
3: #define RESOURCE_H
4: class
5: mybitmap;
6: class
7: resource
8: {
9: public:
10: resource();
11: ~resource();
12: private:
13: mybitmap*
14: m_pBitmap;
15: };
16: #endif
17: resource::~resource()
18: {
19: if (
20: NULL != m_pBitmap )
21: {
22: delete m_pBitmap;
23: }
24: }
程序編譯時,會有一個警告,deletion of pointer to incomplete type 'mybitmap'; no destructor called(沒有實踐)
原因就在於#include和class的區別:class如上面所說,而#include是包括一個類的所有定義、成員和方法等信息。
class A 聲明僅僅告訴程序有這樣一個類,你可以在這里聲明類A的一個指針,但是此處並不能獲得類A的具體信息,如果定義類A的一個指針是可以的,但定義一個類A的對象,則程序是錯誤的,因為不知道A的具體信息,故無法生成一個對象。原因是程序中用class聲明的mybitmap類,在執行delete m_pBitmap時,因為它不知道mybitmap類的具體信息,所以無法調用它的析構函數,故內存並沒有釋放,造成內存泄漏。