C++工作笔记- C++中的动态类型与动态绑定、虚函数、运行时多态的实现
動態類型與靜態類型
靜態類型
? ? ? ? ?是指不需要考慮表達式的執行期語義,僅分析程序文本而決定的表達式類型。靜態類型僅依賴于包含表達式的程序文本的形式,而在程序運行時不會改變。通俗的講,就是上下文無關,在編譯時就可以確定其類型。
動態類型
? ? ? ? 是指由一個左值表達式表示的左值所引用的最終派生對象的類型。例:如果一個靜態類型為“類 B ”的指針p 指向一個繼承于 B的類 D 的對象,則表達式 *p 的動態類型為“D”。引用按照相似規則處理。一般地講,基類的指針和基類引用有可能為動態類型,就是說在運行之前不能夠確定其真實類型。通常我們說,“基類指針指向的對象的實際/真正類型”或“基類引用所引用的對象的實際/真正類型”,就是它們的動態類型。很顯然,這個動態類型是 ?C++ 語言通過指針和引用實現運行時多態能力的核心概念。
動態綁定與靜態綁定
靜態綁定:編譯時綁定,通過對象調用
動態綁定:運行時綁定,通過地址實現
?
只有采用“指針->函數()”或“引用變量.函數()”的方式調用C++類中的虛函數才會執行動態綁定。對于C++中的非虛函數,因為其不具備動態綁定的特征,所以不管采用什么樣的方式調用,都不會執行動態綁定。
即所謂動態綁定,就是基類的指針或引用有可能指向不同的派生類對象,對于非虛函數,執行時實際調用該函數的對象類型即為該指針或引用的靜態類型(基類類型);而對于虛函數,執行時實際調用該函數的對象類型為該指針或引用所指對象的實際類型。比如下面代碼:
class Base {public:void func() {cout << "func() in Base." << endl;}virtual void test() {cout << "test() in Base." << endl;} };class Derived : public Base {void func() {cout << "func() in Derived." << endl;}virtual void test() {cout << "test() in Derived." << endl; } };int main() {Base* b;b = new Derived();b->func();b->test(); }由運行結果可以看到,b是一個基類指針,它指向了一個派生類對象,基類Base里面有兩個函數,其中test為虛函數,func為非虛函數。因此,對于test就表現為動態綁定,實際調用的是派生類對象中的test,而func為非虛函數,因此它表現為靜態綁定,也就是說指針類型是什么,就會調用該類型相應的函數。
?
虛函數、動態綁定、運行時多態之間的關系
?
簡單地說,虛函數是動態綁定的基礎;動態綁定是實現運行時多態的基礎。
要觸發動態綁定,需滿足兩個條件:
(1) ?只有虛函數才能進行動態綁定,非虛函數不進行動態綁定。
(2) ?必須通過基類類型的引用或指針進行函數調用。
通過基類指針或基類引用做形參,當實參傳入不同的派生類(或基類)的指針或引用,在函數內部觸發動態綁定,從而來運行時實現多態的。
?
下面通過實際例子才展示運行時多態的實現方式:
如下代碼是一個Base基類和它的三個派生類Derived1,Derived2,Derived3。
class Base {public:void Print() {cout << "Print() from Base." << endl;}virtual void Display() {cout << "Display() from Base." << endl;} };class Derived1 : public Base {public:void Print() {cout << "Print() from Derived1." << endl;}void Display() {cout << "Display() from Derived2." << endl;} };class Derived2 : public Base {public:void Print() {cout << "Print() from Derived2." << endl;}void Display() {cout << "Display() from Derived2." << endl;} };class Derived3 : public Base {public:void Print() {cout << "Print() from Derived3." << endl;}void Display() {cout << "Display() from Derived3." << endl;} };下面兩個全局函數分別以基類指針和基類引用作形參來實現運行時多態:
//通過基類引用作形參實現多態 void Polymorphic1(Base& b) {b.Print();b.Display(); }//通過基類指針作形參實現多態 void Polymorphic2(Base* b) {b->Print();b->Display(); }
下面是測試代碼:
測試結果如下圖:
?
? ? ? ? 我們看到第一組想對通過基類引用作形參實現多態進行測試,需要將不同派生類的對象作實參傳過去。然而,把派生類放到基類的vector中存儲的過程中,派生類對象被自動轉換為基類對象了,因而實際存儲的均為基類對象,所以再從vector中取出對象元素做實參傳遞的時候,傳遞的均為基類對象,所以測試失敗。
? ? ? ? 對這個比較挫的測試進行的分析和思考:由C++ STL的vector容器中存儲的對象拷貝引起的對capacity屬性 的理解
? ? ? ? 而下面兩組我們分別把不同派生類的指針和對象作實參進行測試,結果顯示均實現了運行時多態:即傳入不同的對象,就會調用該對象相應的Display函數,因為在基類中,Display為虛函數,所以這里它實現了對象的動態綁定,從而實現了運行時多態;與之做對比的Print函數在基類中為非虛構函數,因此對Print函數不會進行動態綁定,而是靜態綁定:即基類指針只能調用基類中的Print函數。
?
?
參考文獻:
1.?http://blog.csdn.net/lynnboy/article/details/154894
2.?http://www.cnblogs.com/chris12/archive/2012/10/28/2744131.html
3.?http://blog.csdn.net/livelylittlefish/article/details/2171521
?
? ? ? ? ?? ?
?
? ? ? ? ? 原創文章,轉載請注明: 轉載自 ?IIcyZhao's Road
?
?
? ? ? ? ? 本文鏈接地址: ?http://blog.csdn.net/iicy266/article/details/11906509
總結
以上是生活随笔為你收集整理的C++工作笔记- C++中的动态类型与动态绑定、虚函数、运行时多态的实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Qt文档阅读笔记-C++与QML混合编程
- 下一篇: C++文档阅读笔记-STL中pair的初