C++的動態綁定和靜態綁定,爲何運行時才能確定動態類型?

1、對象的靜態類型和動態類型 

  1. 對象的靜態類型:對象在聲明時採用的類型。是在編譯期確定的。
  2. 對象的動態類型:目前所指對象的類型,是在運行期決定的。對象的動態類型可以更改,但是靜態類型無法更改。

     關於對象的靜態類型和動態類型,看一個示例:

classB

{

};

classC:publicB

{

};

classD:publicB

{

};

D*pD=newD(); // pD的靜態類型是它聲明的類型D*,動態類型也是D*

B*pB=pD; // pB的靜態類型是它聲明的類型B*,動態類型是pB所指向的對象pD的類型D*

C*pC=newC();

pB=pC; // pB的動態類型是可以更改的,現在它的動態類型是C*

2、靜態綁定和動態綁定 

  1. 靜態綁定:綁定的是對象的靜態類型,某特性(比如函數)依賴於對象的靜態類型,發生在編譯期。
  2. 動態綁定:綁定的是對象的動態類型,某特性(比如函數)依賴於對象的動態類型,發生在運行期。
classB

{

voidDoSomething();

virtualvoidvfun();

};

classC:publicB

{

voidDoSomething(); // 首先說明一下,這個子類重新定義了父類的no-virtual函數,這是一個不好的設計,會導致名稱遮掩;這裏只是爲了說明動態綁定和靜態綁定才這樣使用。

virtualvoidvfun();

};

classD:publicB

{

voidDoSomething();

virtualvoidvfun();

};

D*pD=newD();

B*pB=pD;
  • pD->DoSomething()和pB->DoSomething()調用的不是同一個函數,雖然pD和pB都指向同一個對象。因爲函數DoSomething是一個no-virtual函數,它是靜態綁定的,也就是編譯器會在編譯期根據對象的靜態類型來選擇函數。pD的靜態類型是D*,那麼編譯器在處理pD->DoSomething()的時候會將它指向D::DoSomething()。同理,pB的靜態類型是B*,那pB->DoSomething()調用的就是B::DoSomething()。
  • pD->vfun()和pB->vfun()調用的是同一個函數,因爲vfun是一個虛函數,它動態綁定的,也就是說它綁定的是對象的動態類型,pB和pD雖然靜態類型不同,但是他們同時指向一個對象,他們的動態類型是相同的,都是D*,所以,他們的調用的是同一個函數:D::vfun()。
  • 上面都是針對對象指針的情況,對於引用(reference)的情況同樣適用。指針和引用的動態類型和靜態類型可能會不一致,但是對象的動態類型和靜態類型是一致的。

       D D;

       D.DoSomething()和D.vfun()永遠調用的都是D::DoSomething()和D::vfun()。

  • 至於哪些是動態綁定,哪些是靜態綁定,總結爲一句話:只有虛函數才使用的是動態綁定,其他的全部是靜態綁定

3、一個困惑

看完上述講解你可能有一個疑惑,即:“我看程序代碼時,可以看出實際將會調用的函數,爲何編譯器不能在編譯時確定將要調用的函數

一個示例來解決你的困惑:

Object* obj; 
std::cin >> type; 

switch (type) 
{ 
    case PEOPLE: obj = new People; 
    break; 
    case MUSLIM: obj = new Sheep; 
    break; 
} 

obj->WhichFunc();

此時你還能看出將要調用哪個函數麼?哈哈哈

 

參考:深入理解C++的動態綁定和靜態綁定

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