C++在面向對象編程中,存在著靜態綁定和動態綁定的定義,本節即是主要講述這兩點區分。
我是在一個類的繼承體系中分析的,因此下面所說的對象一般就是指一個類的實例。
首先我們需要明確幾個名詞定義:
從上面的定義也可以看出,非虛函數一般都是靜態綁定,而虛函數都是動態綁定(如此才可實現多態性)。
先看代碼和運行結果:
func(){ std::cout << B : func(){ std::cout << C : func(){ std::cout <<
下面逐步分析測試代碼及結果,
C* pc = C(); B* pb = B(); A* pa = pc; pa = pb; C *pnull = NULL;
pa->func(); pc->func(); pnull->func();
C : pa->func(); pc->func(); pnull->func();
如果為A中的void func()函數添加virtual特性,其他不變,即
func(){ std::cout << pa->func(); pc->func(); pnull->func();
分析:
在上面的例子中,
1. 如果基類A中的func不是virtual函數,那麼不論pa、pb、pc指向哪個子類對象,對func的調用都是在定義pa、pb、pc時的靜態類型決定,早已在編譯期確定了。
同樣的空指針也能夠直接調用no-virtual函數而不報錯(這也說明一定要做空指針檢查啊!),因此靜態綁定不能實現多態;
2. 如果func是虛函數,那所有的調用都要等到運行時根據其指向對象的類型才能確定,比起靜態綁定自然是要有性能損失的,但是卻能實現多態特性;
本文代碼裡都是針對指針的情況來分析的,但是對於引用的情況同樣適用。
至此總結一下:
(《Effective C++ 第三版》條款36),因為這樣導致函數調用由對象聲明時的靜態類型確定了,而和對象本身脫離了關系,沒有多態,也這將給程序留下不可預知的隱患和莫名其妙的BUG;
另外,在動態綁定也即在virtual函數中,要注意默認參數的使用。當缺省參數和virtual函數一起使用的時候一定要謹慎,不然出了問題怕是很難排查。
看下面的代碼:
func( i = std::cout << << i << F : func( i = std::cout << << i << F* pf = E* pe = pf->func(); pe->func(); }
為什麼會有這種情況,請看《Effective C++ 第三版》 條款37。
這裡只給出建議:
綁定。