動態綁定與靜態綁定

C++中,非虛函數都是靜態綁定,而虛函數卻是動態綁定。

爲了能夠更清楚地瞭解靜態綁定與動態綁定,我們可以看下面這個例子:

class B<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

{

public:

     void fun();

     ...

}

class D: public B

{

     ...

}

 

D x;

B *pB = &x;

pB->fun();

 

D *pD = &x;

pD->fun();

 

那麼兩次調用fun()函數是否相同呢?當然,如果D中沒有定義fun()函數,那麼兩次調用的行爲肯定會是一樣的,但是調用過程卻不同。

pB->fun();  //pB爲指向B類型的指針,直接調用B中的fun()函數

pD->fun();  //pD爲指向D類型的指針,編譯器首先在D中查找fun()函數的聲明,沒有找到,然後到D的基類B中去找,找到fun(),停止查找。

 

但如果D中有自己定義的fun()函數,那執行結果就會不同:

pB->fun();  //調用B::fun()

pD->fun();  //調用D::fun()

 

原因就是,(non-virtual)非虛函數都是靜態綁定,也就是說,由於pB被聲明爲指向B類型的指針,那麼通過pB調用的(non-virtual)非虛函數永遠是B所定義的版本,即使pB指向一個類型爲“B的派生類D“的對象。

但另一方面,(virtual)虛函數卻是動態綁定,那麼不管是通過什麼類型的指針調用的這個虛函數,都會根據指針實際指向的對象類型來決定虛函數的調用,而與指針類型無關。如果fun()函數爲虛函數,那麼不管是通過pB還是pD調用fun()函數,都會調用D::fun(),因爲pBpD真正指向的都是同一個類型D的對象。

 

因此在C++中,絕對不要重新定義繼承而來的(non-virtual)非虛函數,因爲這樣的話,函數的調用決定因素不在對象本身,而與調用函數的指針類型有關,這將給程序留下不可預知的隱患。

如上例,任何一個對象D都可能表現出BD的行爲,決定因素不在x對象本身,而在於指向x的指針類型。

同時,絕對不要重新定義一個繼承而來的virtual函數的缺省參數值,因爲缺省參數值都是靜態綁定,而virtual函數卻是動態綁定。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章