c++在物件導向程式設計中,存在著靜態繫結和動態繫結的定義,本節即是主要講述這兩點區分。
我是在乙個類的繼承體系中分析的,因此下面所說的物件一般就是指乙個類的例項。
首先我們需要明確幾個名詞定義:
靜態型別:物件在宣告時採用的型別,在編譯期既已確定;
動態型別:通常是指乙個指標或引用目前所指物件的型別,是在執行期決定的;
靜態繫結:繫結的是靜態型別,所對應的函式或屬性依賴於物件的靜態型別,發生在編譯期;
動態繫結:繫結的是動態型別,所對應的函式或屬性依賴於物件的動態型別,發生在執行期;
從上面的定義也可以看出,非虛函式一般都是靜態繫結,而虛函式都是動態繫結(如此才可實現多型性)。
先看**和執行結果:
class a
};class b : public a
};class c : public a
};
下面逐步分析測試**及結果,
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(); //a::func() pa的靜態型別永遠都是a*,不管其指向的是哪個子類,都是直接呼叫a::func();
2 pc->func(); //c::func() pc的動、靜態型別都是c*,因此呼叫c::func();
3 pnull->func(); //c::func() 不用奇怪為什麼空指標也可以呼叫函式,因為這在編譯期就確定了,和指標空不空沒關係;
如果注釋掉類c中的func函式定義,其他不變,即
class c : public a
;pa->func(); //a::func() 理由同上;
pc->func(); //a::func() pc在類c中找不到func的定義,因此到其基類中尋找;
pnull->func(); //a::func() 原因也解釋過了;
如果為a中的void func()函式新增virtual特性,其他不變,即
class a
};pa->func(); //b::func() 因為有了virtual虛函式特性,pa的動態型別指向b*,因此先在b中查詢,找到後直接呼叫;
pc->func(); //c::func() pc的動、靜態型別都是c*,因此也是先在c中查詢;
pnull->func(); //空指標異常,因為是func是virtual函式,因此對func的呼叫只能等到執行期才能確定,然後才發現pnull是空指標;
分析:
在上面的例子中,
如果基類a中的func不是virtual函式,那麼不論pa、pb、pc指向哪個子類物件,對func的呼叫都是在定義pa、pb、pc時的靜態型別決定,早已在編譯期確定了。
同樣的空指標也能夠直接呼叫no-virtual函式而不報錯(這也說明一定要做空指標檢查啊!),因此靜態繫結不能實現多型;
如果func是虛函式,那所有的呼叫都要等到執行時根據其指向物件的型別才能確定,比起靜態繫結自然是要有效能損失的,但是卻能實現多型特性;
本文**裡都是針對指標的情況來分析的,但是對於引用的情況同樣適用。
至此總結一下靜態繫結和動態繫結的區別:
靜態繫結發生在編譯期,動態繫結發生在執行期;
物件的動態型別可以更改,但是靜態型別無法更改;
要想實現動態,必須使用動態繫結;
在繼承體系中只有虛函式使用的是動態繫結,其他的全部是靜態繫結;
建議:絕對不要重新定義繼承而來的非虛(non-virtual)函式(《effective c++ 第三版》條款36),因為這樣導致函式呼叫由物件宣告時的靜態型別確定了,而和物件本身脫離了關係,沒有多型,也這將給程式留下不可預知的隱患和莫名其妙的bug;
另外,在動態繫結也即在virtual函式中,要注意預設引數的使用。當預設引數和virtual函式一起使用的時候一定要謹慎,不然出了問題怕是很難排查。
看下面的**:
class e
};class f : public e
};void test2()
為什麼會有這種情況,請看《effective c++ 第三版》 條款37。
這裡只給出建議:
絕對不要重新定義乙個繼承而來的virtual函式的預設引數值,因為預設引數值都是靜態繫結(為了執行效率),而virtual函式卻是動態繫結。
面試中被問到的概率題
問題描述 100人坐飛機,第乙個乘客在座位中隨便選乙個坐下,第100人正確坐到自己坐位的概率是?他們分別拿到了從1號到100號的座位,這些乘客會按號碼順序登機並應當對號入座,如果他們發現對應號座位被別人坐了,就會在剩下空的座位隨便挑乙個坐 現在假設1號乘客瘋了 其他人沒瘋 他會在100個座位中隨便選...
C 靜態繫結和動態繫結
c 為了支援多型性,才用了動態繫結和靜態繫結。首先理解四個名詞 1.物件的靜態型別 物件在宣告時採用的型別,是在編譯期確定的。2.物件的動態型別 目前所指物件的型別,是在執行期決定的。class b class c public b class d public b d pd new d pd的靜態...
C 靜態和動態繫結
class a class b public a class c public a 下面逐步分析測試 及結果,c pc new c pc的靜態型別是它宣告的型別c 動態型別也是c b pb new b pb的靜態型別和動態型別也都是b a pa pc pa的靜態型別是它宣告的型別a 動態型別是pa所...