問題:
最近遇到了兩個類a、b相互呼叫的情況,於是想當然的在兩個類a和b的標頭檔案中 #include 了所需的標頭檔案,當然結果編譯報錯了。為什麼呢,a需要b,b需要a,形成了迴圈,違反了程式的確定性原則。**如下圖所示:
如這樣相互包含的問題,可以使用前置宣告來解決。即:在標頭檔案中宣告該類,在實現檔案中包含該類。如下圖所示:
解析:
為什麼這樣使用前置宣告,即在aaa.h中宣告class bbb; 在bbb.h中宣告class aaa; 且成員變數寫為所宣告類的指標變數, 便不會產生相互包含的錯誤呢?
原因在於:class bbb;這種方式僅僅是一種符號宣告,告訴編譯器存在bbb這個類,不會去確定bbb這個類的所佔資源(記憶體)大小和這個類的實現。
上圖中可以看到在aaa.h中定義的是bbb的指標變數或引用變數,而不是普通的bbb變數,這是因為定義指標變數或引用變數,編譯器只需給該變數分配4位元組(32位程式)記憶體,而不用管bbb物件具體需要占用多少記憶體,也不去確定該類的建構函式是如何實現的,這些事情是在建立該物件(即aaa.cpp中:b = new bbb;)時才會去確定;
但是若定義普通的bbb變數:bbb b; 的話,編譯器需要知道b變數占用了多大記憶體,建構函式如何實現,然後計算需要為aaa類分配記憶體大小,這樣只是宣告class bbb;就不行了,否則會報錯:"使用了未定義的類bbb」,解決辦法是#include"bbb.h",又回到了開始的問題。
同理,bbb.h中關於aaa的宣告及變數定義也是如此。
優點:
使用前置變數,即:在標頭檔案中宣告該類,在實現檔案中包含該類。有其一定的優勢,以aaa類為例:
(1)bbb修改後重新編譯的話,因為是前置宣告,所以不需要重新編譯aaa.h;
(2)定義的成員變數為指標變數或引用變數,記憶體固定增加了4(32位程式),減少了aaa類的記憶體占用
大小,這體現在stl的容器裡包含是類的物件還是指標的時候特別有用。
附錄:
這裡附上成員變數宣告為"引用變數"時的用法**:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#pragma once
class
bbb;
class
aaa
;
#include "aaa.h"
aaa::aaa(bbb &x) : b(x)
aaa::~aaa(
void
)
#pragma once
class
aaa;
class
bbb
;
#include "bbb.h"
#include "aaa.h"
bbb::bbb()
bbb::~bbb(
void
)
void
bbb::newaaa()
#include
int
main()
C 前置宣告
特點 被宣告的類不用重新編譯,節省編譯時間 比如a包含乙個指向b的指標,b包含a的乙個例項,這種情況下,使用前置宣告。易錯的點 class date class task1 因為分配器為d分配記憶體的時候,必須要知道 d的大小 主要應用場景是兩個標頭檔案相互包含的場景,建議僅將前置宣告用於解決迴圈引...
C 前置宣告
一般的前置函式宣告 見過最多的前置函式宣告,基本格式 如下 1 include 2 using namespace std 34 void fun char ch,int pvalue,double dvalue 56 void main 714 15void fun char ch,int pva...
C 編譯,前置宣告
class a class b 存在類巢狀的問題,編譯無法通過。採用前置宣告解決 class b class a class b 以上 還是錯誤的,因為在編譯期間對於類的定義需要知道其成員變數型別的大小。將a.b改為指標,因為對於特定的平台指標大小事固定的。如下是編譯四個階段的過錯。其中編譯階段不會...