溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

虛擬繼承

發(fā)布時間:2020-06-06 05:29:34 來源:網(wǎng)絡(luò) 閱讀:379 作者:清幽寧 欄目:移動開發(fā)

在缺省情況下,C++中的繼承是按值組合的一種特殊情況,比如:

class B :virtual  public A{ ... };

每個B類對象都含有其A基類子對象的所有非靜態(tài)數(shù)據(jù)成員,以及在B中聲明的非靜態(tài)數(shù)據(jù)成員。類似地,當(dāng)派生類自己也作為一個基類對象時,如:

class C :virtual  public B{ ... };

C 類對象含有在C中聲明的所有非靜態(tài)數(shù)據(jù)成員,以及其B子對象的所有非靜態(tài)數(shù)據(jù)成員和A子對象的所有非靜態(tài)數(shù)據(jù)成員。

在單繼承下,這種由繼承支持的.特殊形式的按值組合提供了最有效的,最緊湊的對象表示。在多繼承下,當(dāng)一個基類在派生層次中出現(xiàn)多次時就會有問題。 最主要的實際例子是

iostream 類層次結(jié)構(gòu),在下圖 ostream istream 類都從抽象 ios 基類派生而來,而 iostream 類又是從 ostream istream 派生:

虛擬繼承虛擬繼承

class iostream :

         public istream , public ostream { ... };

缺省情況下,每個 iostream 類對象含有兩個 ios 子對象:在 istream 子對象中的實例以及ostream 子對象中的實例。這為什么不好?從效率上而言,存儲 ios 子對象的兩個復(fù)本,浪費了存儲區(qū),因為 iostream 只需要一個實例。而且 ios 構(gòu)造函數(shù)被調(diào)用了兩次,每個子對象一次,更嚴(yán)重的問題是由于兩個實例引起的二義性,例如:任何未限定修飾地訪問 ios 成員都將導(dǎo)致編譯時刻錯誤。到底訪問哪個實例?如果 ostream istream 對其 ios 子對象的初始化稍稍不同,會怎樣呢?怎樣通過 iostream 類保證這一對 ios 值的一致性?在缺省的按值組合機制下,真的沒有好辦法可以保證這一點。

       C++語言的解決方案是,提供另一種可替代“按引用組合”的繼承機制:虛擬繼承。在虛擬繼承下,只有一個共享的基類子對象被繼承,而無論該基類在派生層次中出現(xiàn)多少次。共享的基類子對象被稱為虛擬基類,在虛擬繼承下,基類子對象的復(fù)制及由此而引起的二義性都被消除了。

C++中虛擬繼承的概念

       為了解決從不同途徑繼承來的同名的數(shù)據(jù)成員在內(nèi)存中有不同的拷貝造成數(shù)據(jù)不一致問題,將共同基類設(shè)置為虛基類。這時從不同的路徑繼承過來的同名數(shù)據(jù)成員在內(nèi)存中就只有一個拷貝,同一個函數(shù)名也只有一個映射。這樣不僅就解決了二義性問題,也節(jié)省了內(nèi)存,避免了數(shù)據(jù)不一致的問題。
class 派生類名:virtual 繼承方式  基類名
virtual是關(guān)鍵字,聲明該基類為派生類的虛基類。
在多繼承情況下,虛基類關(guān)鍵字的作用范圍和繼承方式關(guān)鍵字相同,只對緊跟其后的基類起作用。

聲明了虛基類之后,虛基類在進(jìn)一步派生過程中始終和派生類一起,維護(hù)同一個基類子對象的拷貝。

C++虛擬繼承

◇概念:

C++使用虛擬繼承(Virtual Inheritance),解決從不同途徑繼承來的同名的數(shù)據(jù)成員在內(nèi)存中有不同的拷貝造成數(shù)據(jù)不一致問題,將共同基類設(shè)置為虛基類。這時從不同的路徑繼承過來的同名數(shù)據(jù)成員在內(nèi)存中就只有一個拷貝,同一個函數(shù)名也只有一個映射。

◇解決問題:

解決了二義性問題,也節(jié)省了內(nèi)存,避免了數(shù)據(jù)不一致的問題。

◇二義性: 

#include "stdafx.h"

#include <iostream>

using namespace std;

 //Base

 class Base

 {

      public:

                Base(){ cout << "Base called..." << endl; }

                 void print(){ cout << "Base print..." << endl; }

                 private:

                        };


//Sub

class Sub //定義一個類 Sub

{

         public:

                Sub(){ cout << "Sub called..." << endl; }

                 void print(){ cout << "Sub print..." << endl; }

                 private:

                        };


//Child

class Child : public Base, public Sub //定義一個類Child 分別繼承自 Base ,Sub

{

         public:

                Child(){ cout << "Child called..." << endl; }

                 private:

                        };

int main(int argc, char* argv [])

{

         Child c;

        

         //不能這樣使用,會產(chǎn)生二意性,VC下error C2385

                 //c.print(); 

                 //只能這樣使用

                c. Base::print();

        c. Sub::print();

        

        system( "pause");

         return 0;

        }


向AI問一下細(xì)節(jié)
推薦閱讀:
  1. 繼承&派生
  2. JS繼承

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI