c 面試中被問到的靜態繫結和動態繫結

2021-09-25 22:21:34 字數 2463 閱讀 1567

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所...