優點
1.c++前置宣告,可以節約預處理器的展開時間,也就是在編譯的時候速度是增快了,但是伴隨著很多坑。
2.當被前置宣告的類改動後,只需要編譯包含改動類標頭檔案的原始檔,所有使用了前置宣告的原始檔不需要改動
體現1.所有引用testb.h 的其他 .cpp檔案不用再去包含 tem_a 與 util 這倆個類的標頭檔案,這倆個類的檔案testb.cpp 會包含。其他的.cpp 檔案只需鏈結testb.o 檔案即可。這樣有多少個使用到test_b的原始檔就會省多少次相應的標頭檔案展開。
2. 如果util 與 tem_a 的標頭檔案發生變化,只需要test_b 重新編譯即可,其他用到test_b的原始檔不需要重新編譯,只需鏈結新的test_b.o 即可。
#ifndef test_b_h
#define test_b_h
templateclass tem_a;
class util;
class b
private:
tem_a* handle;
};#endif //testb_h
缺點
1.可能引發bug
struct b {};
struct d : b {};
// good_user.cc:
#include "b.h"
void f(b*);
void f(void*);
void test(d* x) // calls f(b*)
//good_user.cc:
struct d;
void f(b*);
void f(void*);
void test(d*x)
2.該型別的名字被修改,我們需要修改所以使用到它的原始檔。
3.std內的類使用前置宣告可能有未定義行為
4.標準c++的規範並沒有定義enum結構的大小。故即使在標頭檔案對enum進行前置宣告,在引用enum的時候,還是無法確定enum的大小,故無法對enum進行前置宣告。
前置宣告的使用
前置宣告只能使用於 指標、引用、函式形參、函式返回值。如果用於類內部的成員變數的宣告,類的繼承列表、stl容器的模板引數都是非法的。
關於模板引數是可以使用前置宣告的,但是如果delete 前置宣告型別的指標是未定義行為。
錯誤1 前置宣告成員類成員變數的宣告
a.h
class a ;
b.h
class a;
class b
b.cpp
#include "a.h"
void b::fun()
main.cpp
#include "b.h"
int main()
g++ -o main.o -c main.cc testb.h:7: error: field 'a_' has incomplete type 錯誤
錯誤2前置宣告用於繼承a.h
class a ;
b.h
class a;
class b:public a
b.cpp
#include "a.h"
void b::fun()
main.cpp
#include "b.h"
int main()
testb.h:4: error: invalid use of incomplete type 'struct a'
testb.h:2: error: forward declaration of 'struct a'
錯誤3 stl容器類模板引數a.h
class a ;
b.h
class a;
class b
b.cpp
#include "a.h"
void b::fun()
main.cpp
#include "b.h"
int main()
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/../../../../include/c++/4.4.6/bits/stl_vector.h: in destructor 'std::_vector_base<_tp, _alloc>::~_vector_base() [with _tp = a, _alloc = std::allocator]':
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/../../../../include/c++/4.4.6/bits/stl_vector.h:208: instantiated from 'std::vector<_tp, _alloc>::vector() [with _tp = a, _alloc = std::allocator]'
testb.h:4: instantiated from here
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/../../../../include/c++/4.4.6/bits/stl_vector.h:132: error: invalid use of incomplete type 'struct a'
testb.h:2: error: forward declaration of 'struct a'
前置宣告幾種常見的使用方法
前置宣告某個具體的類
a.h
class a;
b.hclass a;
前置宣告某個typedef 的型別a.h
class objcet;
typedef object defobject;
b.hclass object;
typedef object defobject;
或者typedef class object defobject;
前置宣告某個作用域內的變數a.h
namespace test;
}b.h
namespace test
pimpl
pimpl 優化。這個是用在前置宣告具體的乙個的實現。比如如下場景它裡面有三個具體的成員, std_class , std_class_b , define_class 這三個是無法直接前置宣告的。必須在相應的標頭檔案中 包含這三個類的標頭檔案。
a.b
class test
std_class a;
std_class_b b;
define_class c;
};
使用 pimpl 優化就可以起到前置宣告的效果。如下面的優化這樣 a.h 就不用包含相應標頭檔案了。
a.b
#include class test ;
a.cc
class test::impl
std_class a;
std_class_b b;
define_class c;
};// class test
void test::fun()
總結
為了編譯效率可以想其他辦法,好好使用include就行。
類前置宣告和標頭檔案包含
類的前置宣告 forward declaration 和包含標頭檔案 include 的區別常常會迷惑我們,特別是涉及兩個類相互包含的時候。因此我們有必要搞清楚二者的區別以及二者的適用場合。首先我們需要問乙個問題是 為什麼兩個類不能互相包含標頭檔案?所謂互相包含標頭檔案,我舉乙個例子 圖層類clay...
使用前置宣告取代包含標頭檔案
c 關於宣告,定義,類的定義,標頭檔案作用,防止標頭檔案在同一編譯單元中重複引用,不具名空間 這篇文章很大程度是受到exceptional c hurb99 書中第四章 compiler firewalls and the pimpl idiom 編譯器防火牆和pimpl慣用法 的啟發,這一章講述了...
C 前置宣告
特點 被宣告的類不用重新編譯,節省編譯時間 比如a包含乙個指向b的指標,b包含a的乙個例項,這種情況下,使用前置宣告。易錯的點 class date class task1 因為分配器為d分配記憶體的時候,必須要知道 d的大小 主要應用場景是兩個標頭檔案相互包含的場景,建議僅將前置宣告用於解決迴圈引...