1. 程式人生 > >c++ 虛繼承與繼承的差異

c++ 虛繼承與繼承的差異

前面一篇文章,說明了在C++ 虛繼承對基類建構函式呼叫順序的影響。經過仔細推敲,發現沒有徹底說清楚虛繼承與普通繼承之間的關係。所以用下面的文字再說明一下。

首先,重複一下虛擬繼承與普通繼承的區別有:

假設derived 繼承自base類,那麼derived與base是一種“is a”的關係,即derived類是base類,而反之錯誤;

假設derived 虛繼承自base類,那麼derivd與base是一種“has a”的關係,即derived類有一個指向base類的vptr。

因此虛繼承可以認為不是一種繼承關係,而可以認為是一種組合的關係。因為虛繼承有著“繼承”兩個關鍵字,那麼大部分人都認為虛繼承與普通繼承的用法沒什麼太大的不同。由此用在繼承體系中,這種將虛繼承認為是普通繼承的危害更佳大。下面先用一個例子來說明問題:

class base
{
public:
    base(){cout<<"base::base()!"<<endl;}
    void printBase(){cout<<"base::printBase()!"<<endl;}
};

class derived:public base
{
public:
    derived(){cout<<"derived::derived()!"<<endl;}
    void printDerived(){cout<<"derived::printDerived()!"<<endl;}
};

上面是普通繼承實現,在實際應用中,我們可以使用下面的程式碼進行型別轉換:

int main(int argc, const char * argv[])
{
    derived oo;
    base oo1(static_cast<base>(oo));
    oo1.printBase();
    derived oo2 = static_cast<derived&>(oo1);
    oo2.printDerived();
    return 0;
}
編譯無錯誤,而且會得出正確的結果。其結果為:
 base::base()!
 derived::derived()!
 base::printBase()!
 derived::printDerived()!

而將上面的普通繼承變成虛擬繼承,如下程式碼:

class base1
{
public:
    base1(){cout<<"base::base()!"<<endl;}
    void printBase(){cout<<"base::printBase()!"<<endl;}
};

class derived1:virtual public base1
{
public:
    derived1(){cout<<"derived::derived()!"<<endl;}
    void printDerived(){cout<<"derived::printDerived()!"<<endl;}
};

int main(int argc, const char * argv[])
{
    derived1 oo;
    base1 oo1(static_cast<base1>(oo));
    oo1.printBase();
    derived1 oo2 = static_cast<derived1&>(oo1);
    oo2.printDerived();
    return 0;
}

編譯上面的程式碼,提示如下:


可以看到不能將基類通過static_cast轉換為繼承類。我們知道c++提供的強制轉換函式static_cast對於繼承體系中的類物件的轉換一般是可行的。那麼這裡為什麼就不可以了呢?還是需要從虛擬繼承的內部實現來說明問題。

virtual base class的原始模型是在class object中為每一個有關聯的virtual base class加上一個指標vptr,該指標指向virtual基類表。有的編譯器是在繼承類已存在的virtual table直接擴充匯入一個virtual base class table。不管怎麼樣由於虛繼承已完全破壞了繼承體系,不能按照平常的繼承體系來進行型別轉換。

不管怎麼樣,虛繼承在型別轉換是一定要十分注意。不要輕易使用虛繼承,更不要在虛繼承的基礎上進行型別轉換,切記切記!

相關推薦

c++ 繼承繼承差異

前面一篇文章,說明了在C++ 虛繼承對基類建構函式呼叫順序的影響。經過仔細推敲,發現沒有徹底說清楚虛繼承與普通繼承之間的關係。所以用下面的文字再說明一下。 首先,重複一下虛擬繼承與普通繼承的區別有: 假設derived 繼承自base類,那麼derived與base是

C++多型繼承基本知識詳解

一、類繼承 C++是一種面向物件的語言,最重要的一個目的就是——提供可重用的程式碼,而類繼承就是C++提供來擴充套件和修改類的方法。類繼承就是從已有的類中派生出新的類,派生類繼承了基類的特性,同時可以新增自己的特性。實際上,類與類之間的關係分為三種:代理、組合和繼承。以下是三種關係的圖解

[C++] 訪問控制繼承詳解

  1、 訪問控制中有三種角色:基類及其友元,派生類,類使用者(物件); 訪問說明符分為public/protected/private,類的成員也相應的分為了3種。   2、 訪問說明符又分為兩種:一個是基類中的成員訪問說明符;另一個是派生類派生列表中的

c++派生類繼承

派生類的建構函式和解構函式 基類的建構函式和解構函式不能被繼承,在派生類中,如果對派生類新增的成員進行初始化,需要加入派生類的建構函式 當派生類建立物件時,首先執行基類的建構函式,隨後執行派生類的建構函式;當撤銷派生類物件時,先執行派生類的解構函式,在執行基

C#單例繼承MonoBehaviour的單例

單例模式是我們最常用的一種設計模式。 主要優點: 1、提供了對唯一例項的受控訪問。 2、由於在系統記憶體中只存在一個物件,因此可以節約系統資源,對於一些需要頻繁建立和銷燬的物件單例模式無疑可以提高系統的效能。 3、允許可變數目的例項。 主要缺點: 1、由於單

c++單繼承繼承(包含虛擬函式繼承的對比)

先來個概念分析題: class Person { public: void Show() { cout<<"Person::"<<_name&l

C++ 鑽石繼承繼承

首先,何為鑽石繼承,顧名思義,在類的繼承過程中,繼承結構是一個類似菱形(鑽石)的結構就屬於鑽石繼承,如下: 這是一個最簡單的鑽石繼承。實際上,在複雜的繼承表中,只要子類按不同的繼承路徑回溯到基類有菱形結構,均屬鑽石繼承。下面先看一個例子,鑽石繼承在C++程式設計中帶來的問

C++繼承基類;虛擬函式繼承

定義:在C++中,在定義公共基類的派生類的時候,如果在繼承方式前使用關鍵字virtual對繼承方式限定,這樣的繼承方式就是虛擬繼承,公共的基類成為虛基類。這樣,在具有公共基類的、使用了虛擬繼承方式的多個派生類的公共派生類中,該基類的成員就只有一份拷貝

c++】深入剖析虛擬繼承各種繼承關係中派生類內成員記憶體分佈情況及基類表的內容

概要 本文講述在VS2012環境下,採用程式碼和圖結合的方法,分析C++程式碼中不同繼承方式的物件模型,以及從彙編角度分析虛擬繼承編譯器生成的虛基類表裡的內容,不涉及虛擬函式。 繼承分類: 1.單繼承 一個子類只有一個直接父類 // 單繼承 工人類 繼承 人類 cl

C++繼承普通繼承的區別

虛繼承的時候在子類的物件中會多出一個叫虛類指標的大小,有的資料說這個指標指向的記憶體裡面包含了該子類的偏移量和到基類的距離。但是我跟蹤過這段記憶體,發現裡面的資料沒有規律,也找不到更多的支撐材料,權且先知道子類的物件裡面會有這麼一個東西吧。 先總結虛擬繼承中比較特殊的地方,

C++ 繼承基類

//聯絡人:石虎 QQ:1224614774 暱稱:嗡嘛呢叭咪哄一、概念1.定義:在多重繼承下,一個基類可以在派生層次中出現多次。(派生類物件中可能出現多個基類物件)在 C++ 中,通過使用虛繼承解決這

C++基類繼承

為什麼有虛繼承 多繼承(Multiple Inheritance)是指從多個直接基類中產生派生類的能力,多繼承的派生類繼承了所有父類的成員。儘管概念上非常簡單,但是多個基類的相互交織可能會帶來錯綜複雜的設計問題,命名衝突就是不可迴避的一個。 多繼承時很容易產生命名衝

C++ 多重繼承繼承

在派生類中對基類成員的訪問應該是唯一的。但是,在多繼承情況下,可能造成對基類中某個成員的訪問出現了不一致的情況,這時就稱對基類成員的訪問產生了二義性。 原因之一:    派生類在訪問基類成員函式時,由於基類存在同名的成員函式,導致無法確定訪問的是哪個基類的成員函式,因

C++繼承的實現方式記憶體佈局

說明:本文給出的結論均是在VS2010下除錯的結果。 一、問題引入 下面的四個類是典型的C++虛繼承的基本結構,現在的問題是這四個類物件的sizeof分別是多少? class Base{ //虛基類 public:

C++虛擬函式繼承繼承

浪費了“黃金五年”的Java程式設計師,還有救嗎? >>>   

C++繼承派生

規則 方法 三種 賦值兼容 順序 spa 構造 指針 rtu 2017-06-25 23:00:59 c++中的繼承和派生是面向對象編程中的一個重要內容,通過繼承可以實現代碼的復用,同時繼承也是實現多態性的基礎。 一、c++繼承的基本形式 class 派生類名:繼承方式 基

C#中的繼承覆蓋

sta 文章 class static color read con public ner 原文發布時間為:2009-03-03 —— 來源於本人的百度文章 [由搬家工具導入]//using System;//using System.Collections.Generic

3.10 C++基類 繼承

set http turn () virt public virtual 這樣的 rtu 參考:http://www.weixueyuan.net/view/6367.html 總結:     本例即為典型的菱形繼承結構,類A中的成員變量及成員函數繼承到類D中均會產生兩份,

C++中class(類)繼承白話學習筆記

double 價格 體積 blog 示例 mes nta size ext 1.class(類) class Drink{//定義飲料類 public://public下面的東西可以被外面訪問 char* type;//飲料種類

C++中繼承抽象類

post dog urn 針對 delet rtu 繼承 prot virt 繼承語法格式如下: class 子類名稱 : 繼承方式(public private protected 三種) 父類名稱 純虛函數格式: virtual 返回值類型 函數名(參數列表)= 0;含