c 前置宣告與標頭檔案引用

2021-08-14 16:05:01 字數 3653 閱讀 5021

優點

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的大小 主要應用場景是兩個標頭檔案相互包含的場景,建議僅將前置宣告用於解決迴圈引...