前面一篇文章,說明了在c++ 虛繼承對基類構造函式呼叫順序的影響。經過仔細推敲,發現沒有徹底說清楚虛繼承與普通繼承之間的關係。所以用下面的文字再說明一下。
首先,重複一下虛擬繼承與普通繼承的區別有:
假設derived 繼承自base類,那麼derived與base是一種「is a」的關係,即derived類是base類,而反之錯誤;
假設derived 虛繼承自base類,那麼derivd與base是一種「has a」的關係,即derived類有乙個指向base類的vptr。
因此虛繼承可以認為不是一種繼承關係,而可以認為是一種組合的關係。因為虛繼承有著「繼承」兩個關鍵字,那麼大部分人都認為虛繼承與普通繼承的用法沒什麼太大的不同。由此用在繼承體系中,這種將虛繼承認為是普通繼承的危害更佳大。下面先用乙個例子來說明問題:
[cpp]
view plain
copy
class
base
; class
derived:
public
base
;
上面是普通繼承實現,在實際應用中,我們可以使用下面的**進行型別轉換:
[cpp]
view plain
copy
intmain(
intargc,
const
char
* argv)
編譯無錯誤,而且會得出正確的結果。其結果為:
base::base()!
derived::derived()!
base::printbase()!
derived::printderived()!
而將上面的普通繼承變成虛擬繼承,如下**:
[cpp]
view plain
copy
class
base1
; class
derived1:
virtual
public
base1
; int
main(
intargc,
const
char
* argv)
編譯上面的**,提示如下:
可以看到不能將基類通過static_cast轉換為繼承類。我們知道c++提供的強制轉換函式static_cast對於繼承體系中的類物件的轉換一般是可行的。那麼這裡為什麼就不可以了呢?還是需要從虛擬繼承的內部實現來說明問題。
virtual base class的原始模型是在class object中為每乙個有關聯的virtual base class加上乙個指標vptr,該指標指向virtual基類表。有的編譯器是在繼承類已存在的virtual table直接擴充匯入乙個virtual base class table。不管怎麼樣由於虛繼承已完全破壞了繼承體系,不能按照平常的繼承體系來進行型別轉換。
不管怎麼樣,虛繼承在型別轉換是一定要十分注意。不要輕易使用虛繼承,更不要在虛繼承的基礎上進行型別轉換,切記切記!
C 鑽石繼承與虛繼承
首先,何為鑽石繼承,顧名思義,在類的繼承過程中,繼承結構是乙個類似菱形 鑽石 的結構就屬於鑽石繼承,如下 這是乙個最簡單的鑽石繼承。實際上,在複雜的繼承表中,只要子類按不同的繼承路徑回溯到基類有菱形結構,均屬鑽石繼承。下面先看乙個例子,鑽石繼承在c 程式設計中帶來的問題。1 2 include3 u...
C 多重繼承與虛繼承
在派生類中對基類成員的訪問應該是唯一的。但是,在多繼承情況下,可能造成對基類中某個成員的訪問出現了不一致的情況,這時就稱對基類成員的訪問產生了二義性。派生類在訪問基類成員函式時,由於基類存在同名的成員函式,導致無法確定訪問的是哪個基類的成員函式,因此出現了二義性錯誤。例如 includeusing ...
C 多繼承與虛繼承
目錄 多繼承與虛繼承以及存在的問題 例子 虛繼承有了多繼承,虛繼承才會有意義 如果有個菱形結構的繼承,爺爺類為a,然後b,c是a的派生類,最後d是b和c的派生類,如果在a中有乙個成員變數a,d去呼叫就會出現訪問不明確,虛繼承就可以解決訪問不明確的這種問題 如果這樣繼承b,c虛繼承了a,virtual...