c++在物件導向程式設計中,存在著靜態繫結和動態繫結的定義,本節即是主要講述這兩點區分。
我是在乙個類的繼承體系中分析的,因此下面所說的物件一般就是指乙個類的例項。
首先我們需要明確幾個名詞定義:
從上面的定義也可以看出,非虛函式一般都是靜態繫結,而虛函式都是動態繫結(如此才可實現多型性)。
先看**和執行結果:
1下面逐步分析測試**及結果,classa2
5};6class b : publica7
10};
11class c : publica12
15};
1 c* pc = new c(); //如果明白上面**的意思,請繼續,pc的靜態型別是它宣告的型別c*,動態型別也是c*;
2 b* pb = new b(); //
pb的靜態型別和動態型別也都是b*;
3 a* pa = pc; //
pa的靜態型別是它宣告的型別a*,動態型別是pa所指向的物件pc的型別c*;
4 pa = pb; //
pa的動態型別可以更改,現在它的動態型別是b*,但其靜態型別仍是宣告時候的a*;
5 c *pnull = null; //
pnull的靜態型別是它宣告的型別c*,沒有動態型別,因為它指向了null;
1 pa->func(); //如果注釋掉類c中的func函式定義,其他不變,即a::func() pa的靜態型別永遠都是a*,不管其指向的是哪個子類,都是直接呼叫a::func();
2 pc->func(); //
c::func() pc的動、靜態型別都是c*,因此呼叫c::func();
3 pnull->func(); //
c::func() 不用奇怪為什麼空指標也可以呼叫函式,因為這在編譯期就確定了,和指標空不空沒關係;
1如果為a中的void func()函式新增virtual特性,其他不變,即class c : publica2
;45 pa->func(); //
a::func() 理由同上;
6 pc->func(); //
a::func() pc在類c中找不到func的定義,因此到其基類中尋找;
7 pnull->func(); //
a::func() 原因也解釋過了;
1分析:在上面的例子中,classa2
5};67 pa->func(); //
b::func() 因為有了virtual虛函式特性,pa的動態型別指向b*,因此先在b中查詢,找到後直接呼叫;
8 pc->func(); //
c::func() pc的動、靜態型別都是c*,因此也是先在c中查詢;
9 pnull->func(); //
空指標異常,因為是func是virtual函式,因此對func的呼叫只能等到執行期才能確定,然後才發現pnull是空指標;
1. 如果基類a中的func不是virtual函式,那麼不論pa、pb、pc指向哪個子類物件,對func的呼叫都是在定義pa、pb、pc時的靜態型別決定,早已在編譯期確定了。
同樣的空指標也能夠直接呼叫no-virtual函式而不報錯(這也說明一定要做空指標檢查啊!),因此靜態繫結不能實現多型;
2. 如果func是虛函式,那所有的呼叫都要等到執行時根據其指向物件的型別才能確定,比起靜態繫結自然是要有效能損失的,但是卻能實現多型特性;
本文**裡都是針對指標的情況來分析的,但是對於引用的情況同樣適用。
至此總結一下靜態繫結和動態繫結的區別:
1. 靜態繫結發生在編譯期,動態繫結發生在執行期;
2. 物件的動態型別可以更改,但是靜態型別無法更改;
3. 要想實現動態,必須使用動態繫結;
4. 在繼承體系中只有虛函式使用的是動態繫結,其他的全部是靜態繫結;
建議:絕對不要重新定義繼承而來的非虛(non-virtual)函式(《effective c++ 第三版》條款36),因為這樣導致函式呼叫由物件宣告時的靜態型別確定了,而和物件本身脫離了關係,沒有多型,也這將給程式留下不可預知的隱患和莫名其妙的bug;
另外,在動態繫結也即在virtual函式中,要注意預設引數的使用。當預設引數和virtual函式一起使用的時候一定要謹慎,不然出了問題怕是很難排查。
看下面的**:
1為什麼會有這種情況,請看《effective c++ 第三版》 條款37。classe2
8};9class f : publice10
16};
1718
void
test2()
19
這裡只給出建議:
絕對不要重新定義乙個繼承而來的virtual函式的預設引數值,因為預設引數值都是靜態繫結(為了執行效率),而virtual函式卻是動態繫結。
C 中的靜態繫結和動態繫結
感謝原作者分享 c 在物件導向程式設計中,存在著靜態繫結和動態繫結的定義,本節即是主要講述這兩點區分。我是在乙個類的繼承體系中分析的,因此下面所說的物件一般就是指乙個類的例項。首先我們需要明確幾個名詞定義 從上面的定義也可以看出,非虛函式一般都是靜態繫結,而虛函式都是動態繫結 如此才可實現多型性 先...
C 靜態繫結和動態繫結
c 為了支援多型性,才用了動態繫結和靜態繫結。首先理解四個名詞 1.物件的靜態型別 物件在宣告時採用的型別,是在編譯期確定的。2.物件的動態型別 目前所指物件的型別,是在執行期決定的。class b class c public b class d public b d pd new d pd的靜態...
靜態繫結和動態繫結
c 中,非虛函式都是靜態繫結,而虛函式卻是動態繫結。為了能夠更清楚地了解靜態繫結與動態繫結,我們可以看下面這個例子 include using namespace std class b 那麼兩次呼叫fun 函式是否相同呢?當然,如果d中沒有定義fun 函式 如例子中 那麼兩次呼叫的行為肯定會是一樣...