0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

C++多繼承的二義性問題

NJ90_gh_bee81f8 ? 來源:未知 ? 作者:李建兵 ? 2018-03-14 15:26 ? 次閱讀

在多重繼承中,需要解決的主要問題是標(biāo)識符不唯一,即二義性問題。比如,當(dāng)在派生類繼承的多個(gè)基類中有同名成員時(shí),派生類中就會出現(xiàn)標(biāo)識符不唯一的情況。

在多重繼承中,派生類由多個(gè)基類派生時(shí),基類之間用逗號隔開,且每個(gè)基類前都必須指明繼承方式,否則默認(rèn)是私有繼承。可以通過以下3種方法解決二義性問題。

使用運(yùn)算符"::";

使用同名覆蓋的原則;

使用虛基類;

1.使用域運(yùn)算符

如果派生類的基類之間沒有繼承關(guān)系,同時(shí)又沒有共同的基類,則在引用同名成員時(shí),可以在成員名前面加上類名和域運(yùn)算符來區(qū)別來自不同基類的成員。

2.使用同名覆蓋的原則

在派生類中重新定義與基類中同名的成員(如果是成員函數(shù),則參數(shù)表也要相同,否則是重載)以屏蔽掉基類中的同名成員,在引用這些同名成員時(shí),引用的就是派生類中的成員。

#include

using namespace std;

class Base

{

public:

int x;

void show()

{

cout << "Base,x= " << x << endl;

}

};

class Derived :public Base

{

public:

int x;

void show()

{

cout << "Derived , x= " << x << endl;

}

};

int main()

{

Derived ob;

ob.x = 5;

ob.show();

ob.Base::show();

ob.Base::x = 12;

ob.Base::show();

system("pause");

return 0;

}

3.虛基類

在多重繼承中,要引用派生類的成員時(shí),先是在派生類自身的作用域內(nèi)尋找,如果找不到再到基類中尋找。這時(shí),如果這些基類有一個(gè)共同的基類,派生類訪問這個(gè)共同基類的成員時(shí),就有可能由于同名成員的問題而發(fā)生二義性,此時(shí)就需要虛基類來解決。

#include

using namespace std;

class Base

{

public:

Base()

{

x = 1;

}

protected:

int x;

};

class Base1 :public Base

{

public:

Base1()

{

cout << "Base1,x= " << x << endl;

}

};

class Base2 :public Base

{

public:

Base2()

{

cout << "Base2,x= " << x << endl;

}

};

class Derived :public Base1, public Base2

{

public:

Derived()

{

cout << "Derived,x= " << x << endl;

}

};

int main()

{

Derived obj;

system("pause");

return 0;

}

上邊的代碼表面上看類Base1和類Base2是從同一個(gè)基類Base派生出來的,但是其對應(yīng)的卻是基類Base的兩個(gè)不同的復(fù)制。因此,當(dāng)派生類Derived要訪問變量x時(shí)不知從哪條路徑去尋找,從而引發(fā)二義性問題。

上述代碼對應(yīng)的類層次結(jié)構(gòu)如圖1所示,屬于非虛基類的類層次結(jié)構(gòu)。要解決該問題,需要引入虛基類,其具體的做法是將公共基類聲明為虛基類,這樣這個(gè)公共基類就只有一個(gè)拷貝,從而不會出現(xiàn)二義性問題。虛基類的類層次結(jié)構(gòu)如圖2所示。

圖 1

圖 2

3.1虛基類

虛基類的聲明是在派生類的聲明過程中進(jìn)行的,其聲明的一般形式為:

class<派生類名>:virtual <派生方式><基類名>

這種派生方式叫做虛擬繼承,虛基類關(guān)鍵字的作用范圍和派生方式與一般派生類的聲明一樣,只對緊跟其后的基類起作用。聲明了虛基類以后,虛基類的成員在進(jìn)一步的派生過程中和派生類一起維護(hù)同一個(gè)內(nèi)存拷貝。

#include

using namespace std;

class Base

{

public:

Base()

{

x = 1;

}

protected:

int x;

};

class Base1 :virtual public Base

{

public:

Base1()

{

cout << "Base1,x= " << x << endl;

}

};

class Base2 :virtual public Base

{

public:

Base2()

{

cout << "Base2,x= " << x << endl;

}

};

class Derived :public Base1, public Base2

{

public:

Derived()

{

cout << "Derived,x= " << x << endl;

}

};

int main()

{

Derived obj;

system("pause");

return 0;

}

在上述代碼中,由于把公共基類Base聲明為類Base1和Base2的虛基類,所以由類Base1和類Base2派生的類Derived只有一個(gè)基類Base,消除了二義性。

3.2虛基類構(gòu)造函數(shù)和初始化

虛基類的初始化與一般的多繼承的初始化在語法上是一樣的,但是構(gòu)造函數(shù)的執(zhí)行順序不同。主要在以下方面:

虛基類的構(gòu)造函數(shù)的執(zhí)行在非虛基類的構(gòu)造函數(shù)之前;

若同一層次中包含多個(gè)虛基類,這些虛基類的構(gòu)造函數(shù)按照他們被聲明的先后順序執(zhí)行;

若虛基類由非虛基類派生而來,則仍然先執(zhí)行基類的構(gòu)造函數(shù),再執(zhí)行派生類的構(gòu)造函數(shù)。

#include

using namespace std;

class Base

{

public:

Base(int x1)

{

x = x1;

cout << "Base,x= " << x << endl;

}

protected:

int x;

};

class Base1 :virtual public Base

{

int y;

public:

Base1(int x1, int y1) :Base(x1)

{

y = y1;

cout << "Base1 ,y=" << y << endl;

}

};

class Base2 :virtual public Base

{

int z;

public:

Base2(int x1, int z1) :Base(x1)

{

z = z1;

cout << "Base2,z= " << z << endl;

}

};

class Derived :public Base1, public Base2

{

int xyz;

public:

Derived(int x1, int y1, int z1, int xyz1) :Base(x1), Base1(x1,y1), Base2(x1,z1)

{

xyz = xyz1;

cout << "Derived,xyz = " << xyz << endl;

}

};

int main()

{

Derived obj(1, 2, 3, 4);

system("pause");

return 0;

}

上邊的代碼中,虛基類Base的構(gòu)造函數(shù)只執(zhí)行了一次,這是因?yàn)楫?dāng)派生類Derived調(diào)用了虛基類Base的構(gòu)造函數(shù)之后,類Base1和Base2對虛基類Base構(gòu)造函數(shù)的調(diào)用就被忽略,這是初始化虛基類和初始化非虛基類的不同。

在使用虛基類時(shí)要注意:

虛基類的關(guān)鍵字virtual與派生方式的關(guān)鍵字public,private,protected的書寫位置無關(guān)緊要,可以先寫虛基類的關(guān)鍵字,也可以先寫派生 方式的關(guān)鍵字;

一個(gè)基類在作為某些類的虛基類的同時(shí)可以作為另一些類的非虛基類;

虛基類構(gòu)造函數(shù)的參數(shù)必須由最新派生出來的類負(fù)責(zé)初始化,即使不是直接繼承也應(yīng)如此。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • C++
    C++
    +關(guān)注

    關(guān)注

    21

    文章

    2100

    瀏覽量

    73453

原文標(biāo)題:C++多繼承的二義性問題

文章出處:【微信號:gh_bee81f890fc1,微信公眾號:面包板社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    C++之STL算法()

    C++之STL算法()
    的頭像 發(fā)表于 07-18 14:49 ?951次閱讀
    <b class='flag-5'>C++</b>之STL算法(<b class='flag-5'>二</b>)

    【好資料系列】C++實(shí)驗(yàn) 繼承與派生——教師工資計(jì)算

    C++實(shí)驗(yàn)繼承與派生——教師工資計(jì)算.doc
    發(fā)表于 08-05 20:41

    【微信精選】C++的精髓類和繼承就該這么理解!

    中的公有成員。C++繼承 以下例子:定義了一個(gè)基類base,定義了一個(gè)子類sum,子類繼承了基類base,#include class sum: public base{public: int add
    發(fā)表于 08-15 09:41

    C++ 繼承類 虛基類分享

    /details/1027495131.繼承派生類有多個(gè)基類或者虛基類,同一個(gè)類不能多次作為某個(gè)派生類的直接基類,但可以作為一個(gè)派生類的間接基類;class QUEUE: STACK, STACK{...
    發(fā)表于 07-02 06:54

    MC三維重建算法的二義性消除研究

    面繪制法進(jìn)行三維重建是三維重建技術(shù)的主要方法,Marching Cubes(移動立方體)算法是經(jīng)典的面繪制法。本文在剖析了MC 算法的基礎(chǔ)上,針對其存在的二義性問題,給出了消除二義性
    發(fā)表于 01-22 12:02 ?21次下載

    C++內(nèi)部類的實(shí)現(xiàn)及應(yīng)用

    多重繼承一直是C++語言中一個(gè)廣受爭議的語言特征。一般認(rèn)為,在面向?qū)ο笤O(shè)計(jì)中應(yīng)該謹(jǐn)慎使用多重繼承。文章分析了C++中多重繼承實(shí)現(xiàn)的復(fù)雜性并對
    發(fā)表于 06-28 17:59 ?50次下載
    <b class='flag-5'>C++</b>內(nèi)部類的實(shí)現(xiàn)及應(yīng)用

    繼承與派生_實(shí)驗(yàn)3

    c++面向?qū)ο笳n程實(shí)驗(yàn)指導(dǎo)書題目_繼承與派生。
    發(fā)表于 01-14 16:25 ?0次下載

    面向?qū)ο蟮某绦蛟O(shè)計(jì)(C++

    面向?qū)ο蟮某绦蛟O(shè)計(jì)(C++).面向?qū)ο蟮幕舅枷? C++C的非面向?qū)ο髷U(kuò)充 繼承性與派生類 類庫和基于C++的良好OOP風(fēng)格。
    發(fā)表于 03-22 14:40 ?0次下載

    C++實(shí)驗(yàn) 繼承與派生——教師工資計(jì)算

    C++實(shí)驗(yàn) 繼承與派生——教師工資計(jì)算
    發(fā)表于 12-30 14:50 ?1次下載

    Visual C++教程之C++的基礎(chǔ)知識介紹

    本文檔的主要內(nèi)容詳細(xì)介紹的是Visual C++教程之C++的基礎(chǔ)知識介紹主要內(nèi)容包括了:1 類和對象,2 類的成員及特性,3 繼承和派生類
    發(fā)表于 02-15 15:59 ?9次下載
    Visual <b class='flag-5'>C++</b>教程之<b class='flag-5'>C++</b>的基礎(chǔ)知識介紹

    C++程序設(shè)計(jì)教程之繼承的詳細(xì)資料說明

    本文檔的詳細(xì)介紹的是C++程序設(shè)計(jì)教程之繼承的詳細(xì)資料說明主要內(nèi)容包括了:1.繼承結(jié)構(gòu) ( Inheritance Structure ) ,2.訪問父類成員 ( Access Father’s
    發(fā)表于 02-22 11:24 ?98次下載
    <b class='flag-5'>C++</b>程序設(shè)計(jì)教程之<b class='flag-5'>繼承</b>的詳細(xì)資料說明

    C++中類的繼承訪問級別學(xué)習(xí)總結(jié)(

    上一篇文章我們介紹了c++中類的繼承學(xué)習(xí)總結(jié);今天我們繼續(xù)來分享c++中類的繼承中的訪問級別的學(xué)習(xí)總結(jié)。一、繼承中的訪問級別學(xué)習(xí):1、子類是
    的頭像 發(fā)表于 12-24 16:10 ?709次閱讀

    STM32 C++編程系列:STM32 C++代碼封裝初探

    一、STM32與面向?qū)ο缶幊躺弦徽轮刑岬搅耍?b class='flag-5'>C++的核心之一就在于面向?qū)ο笏枷搿O啾?b class='flag-5'>C語言常用的面向過程編程,面向?qū)ο缶幊痰膬?yōu)勢在于繼承、封裝、多態(tài)的特性,利用這種思想更有助于我們的程序?qū)崿F(xiàn)模塊化
    發(fā)表于 12-08 11:06 ?13次下載
    STM32 <b class='flag-5'>C++</b>編程系列<b class='flag-5'>二</b>:STM32 <b class='flag-5'>C++</b>代碼封裝初探

    使用Vivado Block Design設(shè)計(jì)解決項(xiàng)目繼承性問題

    使用Vivado Block Design設(shè)計(jì)解決了項(xiàng)目繼承性問題,但是還有個(gè)問題,不知道大家有沒有遇到,就是新設(shè)計(jì)的自定義 RTL 文件無法快速的添加到Block Design中
    的頭像 發(fā)表于 02-13 11:02 ?3036次閱讀

    怎樣在Java中實(shí)現(xiàn)繼承

    Java是一種面向?qū)ο蟮闹辉试S單繼承的語言,那么怎樣在Java中實(shí)現(xiàn)繼承呢? 2 方法 1. 多層繼承 如果要直接繼承類,子類
    的頭像 發(fā)表于 02-17 14:55 ?1278次閱讀