【C++】多重繼承與虛繼承

多重繼承與虛繼承

  • 1.單繼承和多重繼承的區別
  • 2.語法規則
        • 示例代碼:多重繼承子類指定父類的構造
        • 示例代碼:多重繼承子類隱藏父類的同名方法
  • 3.虛繼承解決多重繼承遇到的bug
        • 示例代碼:環狀繼承引發的問題
    • 3.1 虛基類:
    • 3.2 語法規則:
    • 3.3 總結:普通繼承跟虛繼承的區別
    • 3.4 虛基類表:
        • 示例代碼:虛繼承跟普通繼承(沒有使用virtual)的區別

1.單繼承和多重繼承的區別

單繼承:子類只有一個父類
多重繼承:一個類如果具備了多個其它類的特點,就可以使用多重繼承

情況一:子類繼承了多個父類
圓桌: 繼承圓和桌子
騾子: 繼承馬和驢
豹子: 繼承貓科動物和哺乳動物
情況二:A派生出B,B派生出C C接著派生(重點)
直接父類:Cat就是波斯貓的直接父類
間接父類:Animal就是波斯貓的間接父類
Animal --》Cat --》波斯貓 --》其他貓
環狀繼承(菱形繼承)
A動物
哺乳B C貓科
D豹子
產生的問題:
問題一:A被構建了多次,浪費了存儲空間(希望A只構建一次)
問題二:二義性問題,通過D去調用A里面的方法有兩條途徑(一條通過B調用,還有一條通過C調用)

2.語法規則

class  子類的名字:public 父類1,public 父類2  //公有繼承
{}
  • 子類大小: 所有父類大小之和+子類本身的大小,滿足字節對齊
  • 構造函數調用順序:多個父類從左到右調用
  • 析構函數調用順序:多個父類從右到左調用
  • 指定調用父類的構造函數
roundtable(int newr, int  w,int h):circle(newr),desk(w,h)
{}

注意:指定的時候多個父類的順序無所謂,最終父類構造函數調用的順序以當初繼承時候書寫的左右順序為準

示例代碼:多重繼承子類指定父類的構造
#include <iostream>
#include <cstring>
using namespace std;/*多重繼承子類指定父類的構造*/
class Catamount  //貓科動物
{
public:Catamount(){cout<<"貓科構造"<<endl;}Catamount(int n){cout<<"貓科構造,帶int參數: "<<n<<endl;}~Catamount(){cout<<"貓科析構"<<endl;}
};class Mammal //哺乳動物
{
public:Mammal(){cout<<"哺乳構造"<<endl;}Mammal(string name){cout<<"哺乳構造,帶string的參數: "<<name<<endl;}~Mammal(){cout<<"哺乳析構"<<endl;}
};class Leopard:public Mammal,public Catamount
{
public://情況1:部分指定,指定了哺乳動物,沒有指定的依然使用無參構造// Leopard():Mammal("草")// Leopard():Catamount(666)//情況2:完全指定//       完全指定的時候,指定父類構造函數的順序無所謂Leopard():Catamount(888),Mammal("肉")// Leopard():Mammal("肉"),Catamount(888){cout<<"豹子構造"<<endl;}~Leopard(){cout<<"豹子析構"<<endl;}
};int main(int argc,char **argv)
{Leopard l1;return 0;   
}/*
輸出結果:
情況1:哺乳構造,帶string的參數: 草      /     哺乳構造貓科構造                        /     貓科構造,帶int參數: 666豹子構造                        /     豹子構造豹子析構                        /     豹子析構貓科析構                        /     貓科析構哺乳析構                        /     哺乳析構
情況2:哺乳構造,帶string的參數: 肉貓科構造,帶int參數: 888豹子構造豹子析構貓科析構哺乳析構
*/
  • 子類出現跟父類同名的方法(子類隱藏了父類的同名方法)
round.getarea();          //圓桌自己的getarea
round.Circle::getarea();  //圓桌對象調用父類Circle的getarea  
round.Desk::getarea();    //圓桌對象調用父類Desk的getarea  
示例代碼:多重繼承子類隱藏父類的同名方法
#include <iostream>
#include <cstring>
using namespace std;/*多重繼承子類隱藏父類的同名方法
*/
class Catamount  //貓科動物
{
public:void eat(){cout<<"貓科動物吃"<<endl;}
};class Mammal //哺乳動物
{
public:void eat(){cout<<"哺乳動物吃"<<endl;}
};class Leopard:public Mammal,public Catamount
{
public:void eat(){cout<<"豹子吃"<<endl;}
};int main(int argc,char **argv)
{Leopard l1;l1.eat(); //兩個父類的eat都被隱藏//調用父類的eatl1.Mammal::eat();l1.Catamount::eat();return 0;   
}/*
執行結果:豹子吃哺乳動物吃貓科動物吃
*/

3.虛繼承解決多重繼承遇到的bug

示例代碼:環狀繼承引發的問題
#include <iostream>
#include <cstring>
using namespace std;/*環狀繼承引發的問題?問題1:Animal被構建多次浪費了存儲空間,C++希望Animal只構建一次問題2:豹子調用eat方法提示二義性*/
class Animal
{
public:Animal(){cout<<"Animal無參構造了"<<endl;}void eat(){cout<<"Animal eat"<<endl;}
};class Catamount:public Animal  //貓科動物
{
public:Catamount(){cout<<"Catamount無參構造"<<endl;}
};class Mammal:public Animal //哺乳動物
{
public:Mammal(){cout<<"Mammal無參構造"<<endl;}
};class Leopard:public Mammal,public Catamount
{
public:Leopard(){cout<<"Leopard無參構造"<<endl;}
};int main(int argc,char **argv)
{Leopard l1;//編譯報錯:提示eat有二義性// l1.eat();  // error: request for member ‘eat’ is ambiguous//解決問題2:但是無法解決問題1l1.Mammal::eat();l1.Catamount::eat();return 0;   
}/*
執行結果:
問題1: 可以看出Animal類被創建的2次Animal無參構造了Mammal無參構造Animal無參構造了Catamount無參構造Leopard無參構造問題2: 可以解決報錯,但無法解決問題1Animal無參構造了Mammal無參構造Animal無參構造了Catamount無參構造Leopard無參構造Animal eatAnimal eat
*/

3.1 虛基類:

\quad 虛基類使得從多個類(B和C)它們的基類相同,共同的虛基類是(A)派生出(D)的對象只繼承一個基類對象(通俗的講就是子類使用virtual繼承了父類,這個父類就是虛基類)
在這里插入圖片描述

3.2 語法規則:

class  子類:virtual public  父類
class  子類:public virtual 父類
{};
virtualpublic的次序無關緊要

3.3 總結:普通繼承跟虛繼承的區別

  • 虛繼承可以解決二義性和A被構建多次這兩個問題,普通繼承不能解決;虛繼承通過增加一個指針(浪費了一點存儲空間),換取了更高的效率
  • 只要一個類虛繼承了其它類,那么該類所有的對象中都會新增一個指針,該指針專門用來指向系統中虛基類表的首地址

3.4 虛基類表:

C++中專門用來存放虛基類地址的一種數據結構
底層原理如下:
在這里插入圖片描述

示例代碼:虛繼承跟普通繼承(沒有使用virtual)的區別
#include <iostream>
#include <cstring>
using namespace std;/*虛繼承的底層原理(虛繼承跟普通繼承(沒有使用virtual)的區別):1.如果一個子類虛繼承了另外一個父類,子類的地址空間中會多出一個指針2.指針的作用:用來指向虛基類表的首地址
*/
class Animal
{
public:Animal(){cout<<"Animal無參構造了"<<endl;}void eat(){cout<<"Animal eat"<<endl;}
};class Catamount:virtual public Animal  //貓科動物
{
public:Catamount(){cout<<"Catamount無參構造"<<endl;}private:int m_age;
};class Mammal:virtual public Animal //哺乳動物
{
public:Mammal(){cout<<"Mammal無參構造"<<endl;}
};class Leopard:public Mammal,public Catamount
{
public:Leopard(){cout<<"Leopard無參構造"<<endl;}
};int main(int argc,char **argv)
{cout<<"貓科類的大小:"<<sizeof(Catamount)<<endl;  // 貓科類的大小:16cout<<"哺乳類的大小:"<<sizeof(Mammal)<<endl;     // 哺乳類的大小:8return 0;   
}/*
執行結果:Leopard l1;l1.eat(); 時,輸出:Animal無參構造了Mammal無參構造Catamount無參構造Leopard無參構造Animal eat
*/

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/86734.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/86734.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/86734.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

GCC編譯/連接/優化等選項

1. GCC編譯/連接/優化等選項 1. GCC編譯/連接/優化等選項 1.1. 簡介1.2. 常用選項 1.2.1. -c -E -S -o1.2.2. -L<path> -l<library>1.2.3. -D<macro>1.2.4. -I<path> 1.3. 代碼生成和優化 1.3.1. -std<standard>1.3.2. -shared1.3.3. -fPIC1.3.…

FFmpeg 壓縮視頻文件

文章目錄 FFmpeg 壓縮視頻文件基本壓縮命令&#xff08;保持 MP4 格式&#xff09;轉換為其他格式示例&#xff1a;關鍵參數說明&#xff1a;額外優化選項&#xff1a; 在FFmpeg中使用多線程加速1. 幀級多線程 (frame-level multithreading)2. 切片級多線程 (slice-level multi…

Ubuntu 系統通過防火墻管控 Docker 容器

Ubuntu 系統通過防火墻管控 Docker 容器指南 一、基礎防火墻配置 # 啟用防火墻 sudo ufw enable# 允許 SSH 連接&#xff08;防止配置過程中斷聯&#xff09; sudo ufw allow 22/tcp二、Docker 配置調整 # 編輯 Docker 配置文件 sudo vim /etc/docker/daemon.json配置文件內…

虛擬機新增硬盤,與數據掛載

我有個虛擬機&#xff0c;當時選擇了獨立文件&#xff0c;現在遇到個問題&#xff0c;硬盤不夠了&#xff0c;索性加了一個新硬盤&#xff0c;現在想把數據庫的數據映射到這個新的硬盤處理。 羅列硬盤 lsblk我得是sdb是新硬盤 2. 分區 sudo fdisk /dev/sdb交互操作&#xff…

go語言學習 第10章:面向對象編程

第10章&#xff1a;面向對象編程 面向對象編程&#xff08;OOP&#xff09;是一種編程范式&#xff0c;它使用“對象”來表示數據和方法&#xff0c;并通過類來定義對象的結構和行為。Go語言雖然不是傳統的面向對象語言&#xff0c;但它通過結構體&#xff08;struct&#xff…

android計算器代碼

本次作業要求實現一個計算器應用的基礎框架。以下是布局文件的核心代碼&#xff1a; <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"match_parent"andr…

Go 語言接口詳解

Go 語言接口詳解 核心概念 接口定義 在 Go 語言中&#xff0c;接口是一種抽象類型&#xff0c;它定義了一組方法的集合&#xff1a; // 定義接口 type Shape interface {Area() float64Perimeter() float64 } 接口實現 Go 接口的實現是隱式的&#xff1a; // 矩形結構體…

我們來學mysql -- 8.4版本記錄慢查詢

記錄慢查詢 開啟慢查詢的配置查看慢查詢狀態動態開啟慢查詢日志永久開啟配置log_throttle_queries_not_using_indexes 記錄慢查詢對性能的影響實際案例說明第一條記錄第二條記錄第三條記錄第四條記錄 開啟慢查詢的配置 查看慢查詢狀態 - 執行 show variables like slow_quer…

2025 年中國大學生程序設計競賽全國邀請賽(鄭州)暨第七屆CCPC河南省大學生程序設計競賽(補題)

文章目錄 前言F、幻形之路G、直徑與最大獨立集H&#xff0c;樹論函數M&#xff0c; 川陀航空學院總結 前言 本次比賽&#xff0c;只能說太多沒接觸的知識了&#xff0c;還有太容易被題面嚇住。 F、幻形之路 題目鏈接&#xff1a;幻形之路 解題思路&#xff1a; 對于這一題只…

如何使用k8s安裝redis呢

在Kubernetes (k8s) 上安裝Redis 在Kubernetes上安裝Redis有幾種方法&#xff0c;下面我將介紹兩種常見的方式&#xff1a;使用StatefulSet直接部署和使用Helm chart部署。 一、安裝redis 1.1 拉去ARM鏡像&#xff08;7.4.2&#xff09; docker pull registry.cn-hangzhou.ali…

SpringBoot的5種日志輸出規范策略

在企業級應用開發中&#xff0c;合理規范的日志記錄是系統穩定運行、問題排查和性能優化的關鍵保障。 SpringBoot作為流行的Java開發框架&#xff0c;提供了強大而靈活的日志支持&#xff0c;但如何建立統一、高效的日志輸出規范卻是許多團隊面臨的挑戰。 本文將介紹SpringBo…

Python Cookbook-7.11 在 PostgreSQL 中儲存 BLOB

任務 需要將 BLOB 存入一個 PostgreSQL 數據庫。 解決方案 PostgreSQL7.2 以及更新的版本支持大對象,而psycopg 模塊提供了二進制轉義函數: import psycopg,cPickle #連接到數據庫,用你的本機來測試數據庫,并獲得游標 connection = psycopg.connect("dbname = test…

Android端口轉發

如上圖所示&#xff0c;有一個Android設備&#xff0c;Android設備里面有主板&#xff0c;主板上有網絡接口和Wi-Fi&#xff0c;網絡接口通過網線連接了一個網絡攝像頭&#xff0c;這就跟電腦一樣&#xff0c;電腦即可以通過網線接入一個網絡&#xff0c;也可以同時用Wi-Fi接入…

Unity基礎-協程

Unity基礎-協程 四、協程 概述 協程&#xff08;Coroutine&#xff09;&#xff0c;本質上并不是多線程&#xff0c;而是在當前線程中將代碼分時執行&#xff0c;不卡主線程。可以理解為&#xff0c;協程會把可能使主線程卡頓的程序分時分布進行。 協程通常用來&#xff1a;…

UniApp組件封裝,2025年最新HarmonyOS鴻蒙模塊化開發項目式教程

一、環境配置與前置條件 ?開發工具要求? HBuilderX 4.64&#xff08;鴻蒙插件已預裝&#xff09;DevEco Studio 5.0.3.400&#xff08;真機調試必備&#xff09;鴻蒙離線SDK&#xff08;通過HBuilderX導入&#xff0c;每個項目獨立配置&#xff09; ?項目初始化 # 創建Vu…

C++ 精簡知識點

目錄 一、核心語法 1.指針VS引用 2. 類與對象&#xff08;必寫代碼&#xff09; 3. 繼承與多態&#xff08;必寫代碼&#xff09; 4. 模板&#xff08;必寫代碼&#xff09; 5.智能指針 6. 異常處理&#xff08;必寫結構&#xff09; 二、簡答題速記 三、考試應急策略 一…

7.Vue的compute計算屬性

3.8. 【computed】 作用&#xff1a;根據已有數據計算出新數據&#xff08;和Vue2中的computed作用一致&#xff09;。 <template><div class"person">姓&#xff1a;<input type"text" v-model"firstName"> <br>名&am…

在VSCode中借助AI豐富C++Qt應用程序

隨著國內外各類自動化編程助手的普及&#xff0c;作為傳統桌面C開發者&#xff0c;也要及時地用上這樣強大的工具。考慮到網速問題&#xff0c;國外的服務時斷時續&#xff0c;還是傾向于使用一些國產的大語言模型助手。我們今天就來看看在VSCode下使用大語言模型輔助Qt開發。 …

Java八股文——JVM「內存模型篇」

JVM的內存模型介紹一下 面試官您好&#xff0c;您問的“JVM內存模型”&#xff0c;這是一個非常核心的問題。在Java技術體系中&#xff0c;這個術語通常可能指代兩個不同的概念&#xff1a;一個是JVM的運行時數據區&#xff0c;另一個是Java內存模型&#xff08;JMM&#xff0…

RabbitMQ 高可用與可靠性保障實現

RabbitMQ 高可用與可靠性保障實現詳解 一、高可用架構設計1.1 集群部署模式1.2 鏡像隊列&#xff08;Mirrored Queue&#xff09; 二、可靠性保障機制2.1 消息持久化2.2 確認機制&#xff08;Confirm & Ack&#xff09;2.3 死信隊列&#xff08;DLX&#xff09; 三、容災與…