C++父類指標指向子類物件的實現原理

無鞋童鞋發表於2017-08-30

1 前言  
  記得當初阿里面試的時候被問道這個問題,平時自己面對這個方法都習以為常的使用,C++多型和動態繫結不就是這麼實現的嘛,但是還真沒有刻意去關注其中的原理。今天特意看了相關資料,現在分享給大家。
  其實這塊我們需要分為兩種情況來考慮,第一種是類繼承(靜態繫結),第二種是父類中包含虛擬函式(動態繫結)。
2 具體實現  
 2.1 沒有虛擬函式的繼承
  如果以一個基礎類指標指向一個派生類物件,那麼經由該指標只能訪問基礎類定義的函式(靜態繫結)。
  如果以一個派生類類指標指向一個基礎類物件,必須先做強制轉型動作(explicit cast),這種做法很危險,也不符合生活習慣,在程式設計上也會給程式設計師帶來困擾。(一般不會這麼去使用)
  如果基礎類和派生類類定義了相同名稱的成員函式,那麼通過物件指標呼叫成員函式時,到底呼叫那個函式要根據指標的原型來確定,而不是根據指標實際指向的物件型別確定。(指標型別是誰就呼叫誰)
  這塊我需要說明一下為何基礎類可以指向派生類物件,而派生類不去指向父類物件。
  通常來說,子類總是含有一些父類沒有的成員變數,或者方法函式。而子類肯定含有父類所有的成員變數和方法函式。所以用父類指標指向子類時,沒有問題,因為父類有的,子類都有,不會出現非法訪問問題。
  但是如果用子類指標指向父類的話,一旦訪問子類特有的方法函式或者成員變數,就會出現非法,因為被子類指標指向的由父類建立的物件,根本沒有要訪問的那些內容,那些是子類特有的,只有用子類初始化物件時才會有。
 2.2 包含虛擬函式的繼承
  有虛擬函式的繼承,那麼父類指標指向子類物件就是我們常見的多型實現,也就是動態繫結。
  虛擬函式就是為了對“如果你以一個基礎類指標指向一個衍生類物件,那麼通過該指標,你只能訪問基礎類定義的成員函式”這條規則反其道而行之的設計。
  當然這裡還包括純虛擬函式,只要是擁有純虛擬函式的類,就是抽象類,它們是不能夠被例項化的(只能被繼承)。如果一個繼承類沒有改寫父類中的純虛擬函式,那麼他也是抽象類,也不能被例項化。抽象類不能被例項化,不過我們可以擁有指向抽象類的指標,以便於操縱各個衍生類。
2 總結 
  當定義一個指向子類例項的父類指標的時候,記憶體中例項化了子類,由於子類繼承了父類,因此記憶體中的子類裡包含父類的所有成員。但由於生命的時父類指標,因此該指標不能夠訪問子類的成員,而只能訪問父類的成員。然而在父類裡可以宣告純虛擬函式和定義虛擬函式,使用父類指標訪問虛擬函式或純虛擬函式的時候,訪問到的是子類裡重寫的函式。當然,對於虛擬函式,如果子類裡沒有對其重寫的話,仍然訪問到父類裡定義的虛擬函式。可見虛擬函式和純虛擬函式的卻別僅僅在於:純虛擬函式沒有定義,只有宣告。


  參考文獻:
  https://www.zhihu.com/question/31345300
  http://blog.csdn.net/zhouwei1221q/article/details/47953995
  http://www.cnblogs.com/zhangbaochong/p/5380016.html

相關文章