最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

深入解析C++編程中基類與基類的繼承的相關(guān)知識

 更新時間:2016年01月22日 15:29:57   投稿:goldensun  
這篇文章主要介紹了C++編程中基類與基類的繼承的相關(guān)知識,包括多個基類繼承與虛擬基類等重要知識,需要的朋友可以參考下

基類
繼承過程將創(chuàng)建一個新的派生類,它由基類的成員加上派生類添加的任何新成員組成。在多重繼承中,可以構(gòu)建一個繼承關(guān)系圖,其中相同的基類是多個派生類的一部分。下圖顯示了此類關(guān)系圖。

2016122151644636.jpeg (489×200)

單個基類的多個實例
在該圖中,顯示了 CollectibleString 和 CollectibleSortable 的組件的圖形化表示形式。但是,基類 Collectible 位于通過 CollectibleSortableString 路徑和 CollectibleString 路徑的 CollectibleSortable 中。若要消除此冗余,可以在繼承此類類時將其聲明為虛擬基類。

多個基類
如多重繼承中所述,類可以從多個基類派生。在多重繼承模型中(其中,類派生自多個基類),使用 base-list 語法元素指定基類(請參閱概述中的“語法”一節(jié))。例如,可以指定派生自 CollectionOfBook 和 Collection 的 Book 的類聲明:

// deriv_MultipleBaseClasses.cpp
// compile with: /LD
class Collection {
};
class Book {};
class CollectionOfBook : public Book, public Collection {
 // New members
};

指定基類的順序并不重要,只不過在某些情況下,將調(diào)用構(gòu)造函數(shù)和析構(gòu)函數(shù)。在這些情況下,指定基類的順序?qū)⒂绊懀?br /> 構(gòu)造函數(shù)進(jìn)行初始化的順序。如果您的代碼依賴要在 Book 部分之前初始化的 CollectionOfBook 的 Collection 部分,則規(guī)范的順序很重要。按照 base-list 中指定類的順序執(zhí)行初始化。
調(diào)用析構(gòu)函數(shù)以進(jìn)行清理的順序。同樣,如果在銷毀另一部分時必須呈現(xiàn)類的特定“部分”,則順序非常重要。按照與 base-list 中指定類的順序相反的順序調(diào)用析構(gòu)函數(shù)。
注意
基類的規(guī)范順序會影響類的內(nèi)存布局。不要基于內(nèi)存中基成員的順序做出任何編程決策。
當(dāng)指定 base-list 時,不能多次指定同一類名。但是,可以將類多次作為派生類的間接基。

虛擬基類
由于一個類可能多次成為派生類的間接基類,因此 C++ 提供了一種優(yōu)化這種基類的工作方式的方法。虛擬基類提供了一種節(jié)省空間和避免使用多重繼承的類層次結(jié)構(gòu)中出現(xiàn)多義性的方法。
每個非虛擬對象包含在基類中定義的數(shù)據(jù)成員的一個副本。這種重復(fù)浪費了空間,并要求您在每次訪問基類成員時都必須指定所需的基類成員的副本。
當(dāng)將某個基類指定為虛擬基時,該基類可以多次作為間接基而無需復(fù)制其數(shù)據(jù)成員?;惖臄?shù)據(jù)成員的單個副本由將其用作虛擬基的所有基類共享。
當(dāng)聲明虛擬基類時,virtual 關(guān)鍵字將顯示在派生類的基列表中。
請考慮下圖中的類層次結(jié)構(gòu),它演示了模擬的午餐排隊。

2016122151745945.jpeg (247×104)

模擬午餐排隊圖
在該圖中,Queue 是 CashierQueue 和 LunchQueue 的基類。但是,當(dāng)將這兩個類組合成 LunchCashierQueue 時,會出現(xiàn)以下問題:新類包含類型 Queue 的兩個子對象,一個來自 CashierQueue,另一個來自 LunchQueue。下圖顯示了概念上的內(nèi)存布局(實際物理內(nèi)存布局可能會進(jìn)行優(yōu)化)。

2016122151836084.jpeg (183×119)

模擬午餐排隊對象
請注意,Queue 對象中有兩個 LunchCashierQueue 子對象。以下代碼將 Queue 聲明為虛擬基類:

// deriv_VirtualBaseClasses.cpp
// compile with: /LD
class Queue {};
class CashierQueue : virtual public Queue {};
class LunchQueue : virtual public Queue {};
class LunchCashierQueue : public LunchQueue, public CashierQueue {};

virtual 關(guān)鍵字可確保只包含子對象 Queue 的一個副本(請參閱下圖)。

2016122151856486.jpeg (306×80)

使用虛擬基類模擬午餐排隊對象
一個類可以同時具有一個給定類型的虛擬組件和非虛擬組件。下圖演示了這種情況。

2016122151949864.jpeg (442×190)

同一個類的虛擬組件與非虛擬組件
在圖中,CashierQueue 和 LunchQueue 將 Queue 用作虛擬基類。但是,TakeoutQueue 將 Queue 指定為基類而不是虛擬基類。因此,LunchTakeoutCashierQueue 具有類型 Queue 的兩個子對象:一個來自包含 LunchCashierQueue 的繼承路徑,另一個來自包含 TakeoutQueue 的路徑。下圖對此進(jìn)行了演示。

2016122152012278.jpeg (478×104)

帶虛擬和非虛擬繼承的對象布局
注意
與非虛擬繼承相比較,虛擬繼承提供了顯著的大小優(yōu)勢。但是,它可能會引入額外的處理開銷。
如果派生類重寫它從虛擬基類繼承的虛函數(shù),并且派生基類的構(gòu)造函數(shù)或析構(gòu)函數(shù)使用指向虛擬基類的指針調(diào)用該虛函數(shù),則編譯器可能會將其他隱藏的“vtordisp”字段引入到具有虛擬基的類中。/vd0 編譯器選項將禁止添加隱藏的 vtordisp 構(gòu)造函數(shù)/析構(gòu)函數(shù)置換成員。默認(rèn)的 /vd1 編譯器選項會在必要時啟用它們。僅當(dāng)確定所有類構(gòu)造函數(shù)和析構(gòu)函數(shù)以虛擬方式調(diào)用虛函數(shù)時才關(guān)閉 vtordisps。
/vd 編譯器選項會影響整個編譯模塊。使用 vtordisp 雜注可以逐個類地禁用 vtordisp 字段,然后重新啟用這些字段:

#pragma vtordisp( off )
class GetReal : virtual public { ... };
#pragma vtordisp( on )

對于前面的類聲明,如下所示的代碼是不明確的,因為 b 所指的 b 是在 A 中還是在 B 中并不清楚:

C *pc = new C;

pc->b();

名稱多義性
多重繼承使得沿多個路徑繼承名稱成為可能。沿這些路徑的類成員名稱不一定是唯一的。這些名稱沖突稱為“多義性”。
任何引用類成員的表達(dá)式必須采用明確的引用。以下示例說明如何產(chǎn)生多義性:

// deriv_NameAmbiguities.cpp
// compile with: /LD
// Declare two base classes, A and B.
class A {
public:
 unsigned a;
 unsigned b();
};

class B {
public:
 unsigned a(); // Note that class A also has a member "a"
 int b();  // and a member "b".
 char c;
};

// Define class C as derived from A and B.
class C : public A, public B {};

請看前面的示例。由于名稱 a 是類 A 和類 B 的成員,因此編譯器無法辯明哪個 a 指定將調(diào)用函數(shù)。如果成員可以引用多個函數(shù)、對象、類型或枚舉數(shù),則對該成員的訪問是不明確的。
編譯器通過按此順序執(zhí)行測試來檢測多義性:
如果對名稱的訪問是不明確的(如上所述),則會生成錯誤消息。
如果重載函數(shù)是明確的,則將解析它們。(有關(guān)函數(shù)重載多義性的詳細(xì)信息,請參閱參數(shù)匹配。)
如果對名稱的訪問違背了成員訪問權(quán)限,則會生成錯誤消息。(有關(guān)詳細(xì)信息,請參閱成員訪問控制。)
在表達(dá)式通過繼承產(chǎn)生多義性時,您可以通過限定考慮中的名稱及其類名來手動消除該多義性。若要適當(dāng)編譯上面的示例而不產(chǎn)生多義性,請使用如下代碼:

C *pc = new C;

pc->B::a();

注意
在聲明 C 時,如果在 B 的范圍內(nèi)引用 C,則可能會導(dǎo)致出現(xiàn)錯誤。但不會發(fā)出任何錯誤,直到在 B 的范圍內(nèi)實際創(chuàng)建對 C 的非限定引用。
主導(dǎo)
通過一個繼承關(guān)系圖到達(dá)多個名稱(函數(shù)、對象或枚舉器)是可能的。這種情況被視為與非虛擬基類一起使用時目的不明確。這些名稱與虛擬基類一起使用時目的不明確,除非其中一個名稱“決定”其他名稱。
如果某個名稱在兩個類中定義并且一個類派生自另一個類,則該名稱可控制另一個名稱?;鶞?zhǔn)名稱是派生類中的名稱;此名稱在本應(yīng)出現(xiàn)多義性時使用,如以下示例所示:

// deriv_Dominance.cpp
// compile with: /LD
class A {
public:
 int a;
};

class B : public virtual A {
public:
 int a();
};

class C : public virtual A {};

class D : public B, public C {
public:
 D() { a(); } // Not ambiguous. B::a() dominates A::a.
};

不明確的轉(zhuǎn)換
從指向類類型的指針或?qū)︻愵愋偷囊玫娘@式或隱式轉(zhuǎn)換可能會導(dǎo)致多義性。下圖(指向基類的指針的不明確轉(zhuǎn)換)顯示如下內(nèi)容:
D 類型的對象的聲明。
將 address-of 運算符 (&) 應(yīng)用于該對象的效果。請注意,address-of 運算符總是提供該對象的基址。
將使用 address-of 運算符獲取的指針顯式轉(zhuǎn)換為基類類型 A 的效果。請注意,將該對象的地址強(qiáng)制轉(zhuǎn)換為 A* 類型并不總是為編譯器提供足夠的信息,以供 A 類型的子對象進(jìn)行選擇;在這種情況下,將存在兩個子對象。

2016122152113612.jpeg (244×138)

指針到基類的不明確轉(zhuǎn)換
到類型 A*(指向 A 的指針)的轉(zhuǎn)換是不明確的,因為無法辯明 A 類型的哪個子對象是正確的。請注意,您可以通過顯式指定要使用的子對象來避免多義性,如下所示:

(A *)(B *)&d  // Use B subobject.
(A *)(C *)&d  // Use C subobject.

多義性和虛擬基類
如果使用虛擬基類,則函數(shù)、對象、類型和枚舉數(shù)可通過多重繼承路徑到達(dá)。因為僅有一個基類實例,因此在訪問這些名稱時不存在二義性。
下圖顯示如何使用虛擬和非虛擬繼承構(gòu)成對象。

2016122152617748.jpeg (382×146)

虛擬和非虛擬派生
在該圖中,通過非虛擬基類訪問類 A 的任何成員都將導(dǎo)致二義性;編譯器沒有解釋是使用與 B 關(guān)聯(lián)的子對象還是與 C 關(guān)聯(lián)的子對象的信息。但是,將 A 指定為虛擬基類時,訪問哪一個子對象都不成問題。

相關(guān)文章

  • vscode不同項目使用不同的插件的實現(xiàn)

    vscode不同項目使用不同的插件的實現(xiàn)

    本文主要介紹了vscode不同項目使用不同的插件的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07
  • C++求四個正整數(shù)最大公約數(shù)的方法

    C++求四個正整數(shù)最大公約數(shù)的方法

    這篇文章主要介紹了C++求四個正整數(shù)最大公約數(shù)的方法,涉及C++求余算法的運用技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2016-05-05
  • OpenCV實現(xiàn)圖像細(xì)化算法

    OpenCV實現(xiàn)圖像細(xì)化算法

    本文主要介紹了OpenCV實現(xiàn)圖像細(xì)化算法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-08-08
  • 淺析c#中WebBrowser控件的使用方法

    淺析c#中WebBrowser控件的使用方法

    以下是對c#中WebBrowser控件的使用方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-07-07
  • 使用matlab繪制七夕表白玫瑰花束

    使用matlab繪制七夕表白玫瑰花束

    又是一年七夕節(jié)要到了,每年一次直男審美MATLAB繪圖大賽開始了,于是今年對我之前寫的老代碼進(jìn)行了點優(yōu)化組合,整了個花球變花束,感興趣的小伙伴可以動手試一試
    2023-08-08
  • 一篇文章帶你了解C語言內(nèi)存對齊公式

    一篇文章帶你了解C語言內(nèi)存對齊公式

    這篇文章主要介紹了C語言內(nèi)存對齊,包括內(nèi)存對其的基本概念及用法,以及注意事項,并以實例形式加以說明,需要的朋友可以參考下,希望能給你帶來幫助
    2021-08-08
  • C++中產(chǎn)生臨時對象的情況及其解決方案

    C++中產(chǎn)生臨時對象的情況及其解決方案

    這篇文章主要介紹了C++中產(chǎn)生臨時對象的情況及其解決方案,以值傳遞的方式給函數(shù)傳參,類型轉(zhuǎn)換以及函數(shù)需要返回對象時,并給對應(yīng)給出了詳細(xì)的解決方案,通過圖文結(jié)合的方式講解的非常詳細(xì),需要的朋友可以參考下
    2024-05-05
  • C語言 以數(shù)據(jù)塊的形式讀寫文件詳解及實現(xiàn)代碼

    C語言 以數(shù)據(jù)塊的形式讀寫文件詳解及實現(xiàn)代碼

    本文主要介紹 C語言 以數(shù)據(jù)塊的形式讀寫文件,這里對相關(guān)知識資料做了整理,并附代碼示例,以便大家學(xué)習(xí)參考,有學(xué)習(xí)此部分知識的朋友可以參考下
    2016-08-08
  • c語言實現(xiàn)24小時制轉(zhuǎn)換為12小時制示例

    c語言實現(xiàn)24小時制轉(zhuǎn)換為12小時制示例

    這篇文章主要介紹了c語言實現(xiàn)24小時制轉(zhuǎn)換為12小時制示例,需要的朋友可以參考下
    2014-04-04
  • WIN32程序獲取父進(jìn)程ID的方法

    WIN32程序獲取父進(jìn)程ID的方法

    這篇文章主要介紹了WIN32程序獲取父進(jìn)程ID的方法,在進(jìn)行windows程序開發(fā)的時候有一定的實用價值,需要的朋友可以參考下
    2014-08-08

最新評論

塔城市| 武功县| 广灵县| 禹州市| 博客| 永宁县| 宁阳县| 长沙市| 岐山县| 长岛县| 砀山县| 响水县| 东丰县| 林芝县| 凤阳县| 阿克苏市| 错那县| 蒙城县| 阿合奇县| 偃师市| 怀远县| 宝坻区| 永嘉县| 隆回县| 民权县| 呼玛县| 贵港市| 东至县| 井冈山市| 顺义区| 吉林市| 远安县| 西乌珠穆沁旗| 蕉岭县| 惠安县| 荆门市| 聂荣县| 墨竹工卡县| 茂名市| 集贤县| 来安县|