中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

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

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

C++虛繼承解說

發布時間:2020-07-26 15:13:44 來源:網絡 閱讀:720 作者:844133395 欄目:編程語言

1.概括

    在CPlusPlus多繼承編程中時常遇到這樣一個問題--若子類實現多個基類或接口繼承,多基類或接口中存在成員名相同,在客戶與實現類之間的通信時編譯器報錯“不能這樣使用,會產生二義性”由于這個問題的解決方法很多。比如說,可以把相同的成員名給改過來。但是,從專業的角度,可能虛擬繼承會解決這個問題。那接下來我看看c++是怎么避免這種問題的。


2.概念

    當在多條繼承路徑上有一個公共的基類,在這些路徑中的某幾條匯合處,這個公共的基類就會產生多個實例(或多個副本),若只想保存這個基類的一個實例,可以將這個公共基類說明為虛基類。       class 派生類名:virtual 繼承方式  基類名    

    virtual是關鍵字,聲明該基類為派生類的虛基類。    

    例如:     

    class 派生類: virtual 基類1,virtual 基類2,...,virtual 基類n
    
    {
        
        ...//派生類成員聲明
    
    };

    在多繼承情況下,虛基類關鍵字的作用范圍和繼承方式關鍵字相同,只對緊跟其后的基類起作用。 聲明了虛基類之后,虛基類在進一步派生過程中始終和派生類一起,維護同一個基類子對象的拷貝。C++使用虛擬繼承(Virtual Inheritance),解決從不同途徑繼承來的同名的數據成員在內存中有不同的拷貝造成數據不一致問題,將共同基類設置為虛基類。這時從不同的路徑繼承過來的同名數據成員在內存中就只有一個拷貝,同一個函數名也只有一個映射。這樣帶來的有點是解決了二義性問題,也節省了內存,避免了數據不一致的問題。


3.用例

二義性:

#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;
  //不能這樣使用,會產生二意性,VC下error C2385 
  //c.print();  
 
 //只能這樣使用 
  c.Base::print();
  c.Sub::print();
  system("pause");
  return 0;
  }


多重繼承:

//說明:C++虛擬繼承學習演示  
//環境:VS2005  
//blog:pppboy.blog.163.com  
//----------------------------------------------------  
#include "stdafx.h"  
#include <iostream>
using namespace std;  
int gFlag = 0;  
class Base  
{
public:  
 Base(){cout << "Base called : " << gFlag++ << endl;}  
 void print(){cout << "Base print" <<endl;}  
};

class Mid1 : public Base  
{
 public:  
 Mid1(){cout << "Mid1 called" << endl;}  
 private:  
};

class Mid2 : public Base  
{
public:  
 Mid2(){cout << "Mid2 called" << endl;}  
};

class Child:public Mid1, public Mid2  
{
public:  
 Child(){cout << "Child called" << endl;}  
};

int main(int argc, char* argv[])  
{
Child d;
//不能這樣使用,會產生二意性  
     //d.print();  
//只能這樣使用  
d.Mid1::print();
d.Mid2::print();
system("pause");  
return 0;  
}

output:

Base called : 0
 Mid1 called
 Base called : 1
 Mid2 called
 Child called
 Base print
 Base print

虛擬繼承:

#include "stdafx.h"  
#include <iostream>
using namespace std;  
int gFlag = 0;  
class Base  
{
public:  
Base(){cout << "Base called : " << gFlag++ << endl;}  
void print(){cout << "Base print" <<endl;}  
};

class Mid1 : virtual public Base  
{
public:  
Mid1(){cout << "Mid1 called" << endl;}  
private:  
};

class Mid2 : virtual public Base  
{
public:  
Mid2(){cout << "Mid2 called" << endl;}  
};

class Child:public Mid1, public Mid2  
{
public:  
Child(){cout << "Child called" << endl;}  
};

int main(int argc, char* argv[])  
{
Child d;
//這里可以這樣使用  
d.print();
//也可以這樣使用  
d.Mid1::print();
d.Mid2::print();
system("pause");  
return 0;  
}


4.總結

    在多繼承情況下,虛基類關鍵字的作用范圍和繼承方式關鍵字相同,只對緊跟其后的基類起作用。聲明了虛基類之后,虛基類在進一步派生過程中始終和派生類一起,維護同一個基類子對象的拷貝。觀察類構造函數的構造順序,拷貝也只有一份。


5.擴展

    windows編程的程序員們在進行COM編程的時候會遇到這樣的一個問題------繼承接口IUnknown這一塊使用非虛擬繼承。這是為什么呢?如果有這樣的疑問是很正常。之所以這樣是由于會導致與COM不兼容的vtbl。比如:

    struct IX : public IUnknown

    {

        //....

    };

    struct IY : public IUnknow

    {

        //....

    };


 客戶程序實現:

...
if(iid == IID_IUnknown) {
        //the client wants the IUnknown interface.
        *ppv = static_cast<IX*>(this);
    } else if(iid == IID_IX){
        //the client wants the IX interface.
     *ppv = static_cast<IX*>(this);
    } else if(iid == IID_IY) {
        *ppv = static_cast<IY*>(this);
    }
    ...

    可見,程序中他們是通過類型轉換的。不然,IX和IY的vtbl中的頭三個函數指向的將不是IUnknown的三個成員函數。

    


    

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

五大连池市| 禹城市| 秭归县| 双牌县| 格尔木市| 揭东县| 定陶县| 垣曲县| 镇康县| 尚志市| 巫山县| 清水河县| 奇台县| 即墨市| 改则县| 凌海市| 莲花县| 仙桃市| 若尔盖县| 延边| 航空| 阿克陶县| 科尔| 大方县| 高唐县| 湖南省| 定陶县| 宣武区| 比如县| 商水县| 乌拉特前旗| 鞍山市| 龙里县| 晋江市| 白银市| 沙湾县| 雷州市| 同德县| 白山市| 大竹县| 丰台区|