C++----繼承

一、繼承的基本概念

本質:代碼復用+類關系建模(是多態的基礎)

class Person { /*...*/ };
class Student : public Person { /*...*/ }; // public繼承
  • 派生類繼承基類成員(數據+方法),可以通過監視窗口檢驗成員復用。

二、繼承中的訪問權限控制

訪問權限變化表

基類成員訪問限定符/繼承方式public繼承protected繼承private繼承
public成員->派生類public->派生類protected->派生類private
protected成員->派生類protected->派生類protected->派生類private
private成員不可見(但存在)不可見(但存在)不可見(但存在)

關鍵規則

  1. private成員:在派生類中始終不可訪問(但存在于對象中)
  2. protected成員:專為繼承設計,派生類可訪問,外部不可訪問。
  3. 訪問權限計算:Min(成員在基類的權限,繼承方式),權限等級:public>protected>private
  4. 默認繼承方式:class默認private繼承;struct默認public繼承。
  5. 實際開發:優先使用public繼承(占實際使用90%以上),慎用protected/private繼承。

三、對象賦值轉換規則

允許的操作

Student s;
Person p = s;         // 對象切片(調用拷貝構造)
Person& rp = s;       // 直接引用基類部分
Person* pp = &s;      // 直接指向基類部分

禁止的操作

// Person p;
// Student s = p;       // 錯誤!基類無法賦給派生類

關鍵注意

  • 對象切片:派生類->基類賦值時,丟失派生類特有成員。
  • 引用轉換原理:派生類對象包含完整的基類子對象,無臨時變量生成。

? ? ? ? 類型系統對比:

  int i = 0;const double& rd = i;  // 需要const引用(臨時變量具有常性)

四、繼承中的作用域

核心規則

  1. 獨立作用域:基類和派生類擁有獨立的作用域。
  2. 隱藏/重定義:派生類成員與基類同名時,隱藏基類成員,包括成員變量和函數(無論參數是否一致)。
    class Base {
    public:void func(int) {}
    };class Derived : public Base {
    public:void func() { Base::func(42); // 必須顯式指定作用域}
    };

重要細節

  • 函數隱藏與重載:派生類會隱藏基類所有同名函數(即使參數不同)
  • 訪問被隱藏成員:使用作用域解析符
    Base::member
  • 設計建議:避免定義同名非虛函數

五、派生類默認成員函數

1. 構造函數

  • 規則

1.當基類存在默認構造函數時:如果基類有隱式或顯式的無參構造函數(即默認構造函數),派生? ? ?類的構造函數初始化列表不需要顯式調用基類構造函數。編譯器會自動隱式調用基類的默認構造? ? ?函數。示例:

class Person {
public:Person() {} // 默認構造函數(可以隱式生成)
};class Student : public Person {
public:Student() {} // 隱式調用 Person::Person()
};

2.當基類沒有默認構造函數時:如果基類的構造函數需要參數,且沒有定義無參構造函數,則派生類必須在初始化列表中顯示調用基類的某個構造函數,否則會編譯報錯。示例:

class Person {
public:Person(int x) {} // 沒有默認構造函數
};class Student : public Person {
public:Student() : Person(42) {} // 必須顯式調用基類構造函數
};
  • 原理:基類成員初始化順序優先于派生類成員

?2. 拷貝構造函數

  • 規則:需顯式調用基類拷貝構造,完成基類部分的深拷貝

  • 代碼示例

    Student(const Student& s): Person(s)         // 切片調用基類拷貝構造, _id(s._id) {}

3. 賦值運算符重載?

  • 規則:需要顯式調用基類賦值運算符,處理自賦值情況

  • 代碼示例

    Student& operator=(const Student& s) {if (this != &s) {Person::operator=(s);  // 顯式調用基類賦值_id = s._id;}return *this;
    }

4. 析構函數?

  • 規則

    • 析構順序:派生類->基類(自動調用基類析構)

    • 禁止顯式調用基類析構函數

  • 代碼示例

    ~Student() {// 自動調用Person::~Person()delete _ptr;  // 先清理派生類資源
    }

六、繼承關系與友元?

  • 規則:基類友元不能訪問派生類私有成員,需要額外聲明

  • 代碼示例

    class Student;  // 前向聲明
    class Person {friend void Display(const Person&, const Student&);
    };
    class Student : public Person {friend void Display(const Person&, const Student&);
    };
    void Display(const Person& p, const Student& s) {cout << p._name << endl;    // 訪問基類保護成員cout << s._stuNum << endl;  // 訪問派生類保護成員
    }

七、靜態成員與繼承?

  • 特性

    • 基類靜態成員被所有派生類共享

    • 繼承的是訪問權而非副本

    • 靜態成員不被包含在對象中,它放在靜態存儲器。

  • 代碼示例

    class Person
    {
    public :Person () {++ _count ;}
    protected :string _name ; // 姓名
    public :static int _count; // 統計人的個數。
    };
    int Person :: _count = 0;class Student : public Person
    {
    protected :int _stuNum ; // 學號
    };class Graduate : public Student
    {
    protected :string _seminarCourse ; // 研究科目
    };void TestPerson()
    {Student s1 ;Student s2 ;Student s3 ;Graduate s4 ;cout <<" 人數 :"<< Person ::_count << endl; //輸出:人數 :4Student ::_count = 0;cout <<" 人數 :"<< Person ::_count << endl; //輸出:人數 :0
    }

八、復雜繼承模型?

  • 單繼承:一個子類只有一個直接父類時稱這個繼承關系為單繼承

  • 多繼承:一個子類有兩個或以上直接父類時稱這個繼承關系為多繼承

菱形繼承:多繼承的一種特殊情況

問題

數據冗余和二義性(從下面的對象成員模型構造,可以看出菱形繼承有數據冗余和二義性的問題。在Assistant的對象中Person成員會有兩份。)

class Person
{
public :string _name ; // 姓名
};
class Student : public Person
{
protected :int _num ; //學號
};
class Teacher : public Person
{
protected :int _id ; // 職工編號
};
class Assistant : public Student, public Teacher
{
protected :string _majorCourse ; // 主修課程
};void Test ()
{// 這樣會有二義性無法明確知道訪問的是哪一個Assistant a ;    a._name = "peter";    // 需要顯示指定訪問哪個父類的成員可以解決二義性問題,但是數據冗余問題無法解決a.Student::_name = "xxx";a.Teacher::_name = "yyy";
}

解決方案

虛擬繼承(在Assistant的對象中Person成員只有一份。)

class Person
{
public :string _name ; // 姓名
};
class Student : virtual public Person
{
protected :int _num ; //學號
};
class Teacher : virtual public Person
{
protected :int _id ; // 職工編號
};
class Assistant : public Student, public Teacher
{
protected :string _majorCourse ; // 主修課程
};void Test ()
{Assistant a ;a._name = "peter";
}

虛擬繼承解決數據冗余和二義性的原理

講解

為了研究虛擬繼承原理,我們給出了一個簡化的菱形繼承繼承體系,再借助內存窗口觀察對象成員的模型。

class A { int _a; };
class B : public A { int _b; };
class C : public A { int _c; };
class D : public B, public C { int _d; };int main()
{D d;d.B::_a = 1;d.C::_a = 2;d._b = 3;d._c = 4;d._d = 5;return 0;
}

下圖是菱形繼承的內存對象成員模型:這里可以看到數據冗余
下圖是菱形虛擬繼承的內存對象成員模型:這里可以分析出D對象中將A放到的了對象組成的最下
面,這個A同時屬于B和C,那么B和C如何去找到公共的A呢? 這里是通過了 B C 的兩個指針,指向的一張表。這兩個指針叫虛基表指針,這兩個表叫虛基表。虛基表中存的偏移量。通過偏移量
可以找到下面的A
  • 疑問1:為什么D中B和C部分要去找屬于自己的A?

????????那么大家看看當下面的賦值發生時,d是不是要去找出B/C成員中的A才能賦值過去?

  • 疑問2: 為什么要在B和C中存指針,而不直接存距離A的偏移量呢?

? ? ? ? ①存儲內容多樣性:

? ? ? ? ? ? - 多偏移量:菱形繼承中,虛基表除存當? ? ? ? ? ? ? ? ? ?前類到虛基類偏移量,在多重繼承、復? ? ? ? ? ? ? ? ? ?雜模板實例化等場景,還需存不同條件? ? ? ? ? ? ? ? ? ?下訪問虛基類的其他偏移量,用于正確? ? ? ? ? ? ? ? ? ?定位成員。
? ? ? ? ? ? - 輔助信息:虛基表存儲虛基類構造、析? ? ? ? ? ? ? ? ? ?構函數指針等輔助信息,確保在對象構? ? ? ? ? ? ? ? ? ?構造、析構及函數調用時正確操作。僅? ? ? ? ? ? ? ? ? ?用偏移量無法存儲這些信息,易致錯誤。

? ? ? ? ②支持復雜偏移關系:

? ? ? ? ? ? - 適應結構變化:使用虛基表指針,面對? ? ? ? ? ? ? ? ? ?復雜繼承結構變化(如 B、C 繼承路徑? ? ? ? ? ? ? ? ? ? ?新增虛繼承層次)時,虛基表可添加新? ? ? ? ? ? ? ? ? ?偏移量或信息,指針仍能正確指向,保? ? ? ? ? ? ? ? ? ?證虛基類成員訪問。直接用偏移量,結? ? ? ? ? ? ? ? ? ?構變化時需多處修改,維護擴展困難。

下面是上面的Person關系菱形虛擬繼承的原理圖:

九、繼承與組合的選擇

特征繼承組合
關系性質"is-a"關系"has-a"關系
可見性白箱復用(了解實現細節)黑箱復用(接口隔離)
耦合度高耦合低耦合
多態支持支持不支持
代碼復用方式垂直復用(擴展功能)水平復用(功能組合)

使用建議

  1. 優先使用對象組合

  2. 需要多態特性時使用繼承

  3. 避免過度使用多繼承

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

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

相關文章

已驗證正常,Java輸入字符串生成PDF文件

Java輸入字符串生成PDF文件過程&#xff1a; 在Java開發中&#xff0c;如何將字符串轉換為 PDF 是一個常見的需求。網上找了很多例子都無法生成&#xff0c;經過多次嘗試&#xff0c;終于實現了&#xff0c;特此記錄一下。 1、引入pom.xml 添加所需的依賴 <dependency>&…

Mac M1 Comfyui 使用MMAudio遇到的問題解決?

問題1: AssertionError: Torch not compiled with CUDA enabled&#xff1f; 解決辦法&#xff1a;修改代碼以 CPU 運行 第一步&#xff1a;找到 /ComfyUI/custom_nodes/ComfyUI-MMAudio/mmaudio/ext/autoencoder/vae.py文件中的下面這兩行代碼 self.data_mean nn.Buffer(t…

從 .NET Framework 升級到 .NET 8 后 SignalR 問題處理與解決方案

隨著 .NET Framework 向 .NET 8 的遷移&#xff0c;許多開發者在使用 SignalR 時遇到了一些前后端連接、配置、調用等方面的問題。尤其是在處理 SignalR 實時通信功能時&#xff0c;升級后的一些兼容性問題可能導致應用程序無法正常工作。本文將介紹在從 .NET Framework 升級到…

2025.2.5——五、[網鼎杯 2020 青龍組]AreUSerialz 代碼審計|反序列化

題目來源&#xff1a;BUUCTF [網鼎杯 2020 青龍組]AreUSerialz 目錄 一、打開靶機&#xff0c;整理信息 二、解題思路 step 1&#xff1a;代碼審計 step 2&#xff1a;開始解題 突破protected訪問修飾符限制 三、小結 一、打開靶機&#xff0c;整理信息 直接得到一串ph…

Docker深度解析:安裝各大環境

安裝 Nginx 實現負載均衡&#xff1a; 掛載 nginx html 文件&#xff1a; 創建過載目錄&#xff1a; mkdir -p /data/nginx/{conf,conf.d,html,logs} 注意&#xff1a;在掛載前需要對 conf/nginx.conf 文件進行編寫 worker_processes 1;events {worker_connections 1024; …

docker啟動報錯code=exited, status=1/FAILURE——問題排查

問題 在某臺centos7機器上&#xff0c;啟動docker服務 sudo systemctl start docker報下列錯誤&#xff1a; ● docker.service - Docker Application Container EngineLoaded: loaded (/usr/lib/systemd/system/docker.service; enabled; vendor preset: disabled)Active: …

基于SpringBoot養老院平臺系統功能實現五

一、前言介紹&#xff1a; 1.1 項目摘要 隨著全球人口老齡化的不斷加劇&#xff0c;養老服務需求日益增長。特別是在中國&#xff0c;隨著經濟的快速發展和人民生活水平的提高&#xff0c;老年人口數量不斷增加&#xff0c;對養老服務的質量和效率提出了更高的要求。傳統的養…

PostGIS:使用shp2pgsql、pgsql2shp、OGR2OGR函數進行數據導入、導出

數據導入與導出函數 數據庫數據導入與導出可以通過多個函數完成&#xff0c;QGIS文檔介紹了3個函數&#xff1a; shp2pgsql、pgsql2shp、OGR2OGR&#xff0c;分別用于shp導入數據庫、數據庫文件導出為shp、數據轉換為多種數據格式。 &#xff08;1&#xff09;shp2pgsql 在l…

【AIGC魔童】DeepSeek v3推理部署:vLLM/SGLang/LMDeploy

【AIGC魔童】DeepSeek v3推理部署&#xff1a;vLLM/SGLang/LMDeploy &#xff08;1&#xff09;使用vLLM推理部署DeepSeek&#xff08;2&#xff09;使用SGLang推理部署DeepSeek&#xff08;3&#xff09;使用LMDeploy推理部署DeepSeek &#xff08;1&#xff09;使用vLLM推理部…

《AI “造臉術”:生成對抗網絡打造超真實虛擬人臉》

在科技飛速發展的當下&#xff0c;人工智能的浪潮席卷而來&#xff0c;其中生成對抗網絡&#xff08;GANs&#xff09;技術以其獨特的魅力&#xff0c;成為了生成高度真實感虛擬人臉的強大引擎。無論是影視制作中虛擬角色的塑造&#xff0c;還是游戲領域中多樣化角色形象的構建…

C語言的靈魂——指針(2)

前言&#xff1a;上期我們介紹了如何理解地址&#xff0c;內存&#xff0c;以及指針的一些基礎知識和運算&#xff1b;這期我們來介紹一下const修飾指針&#xff0c;野指針&#xff0c;assert斷言&#xff0c;指針的傳址調用。 上一篇指針&#xff08;1&#xff09; 文章目錄 一…

Android studio 創建aar包給Unity使用

1、aar 是什么&#xff1f; 和 Jar有什么區別 aar 和 jar包 都是壓縮包&#xff0c;可以使用壓縮軟件打開 jar包 用于封裝 Java 類及其相關資源 aar 文件是專門為 Android 平臺設計的 &#xff0c;可以包含Android的專有內容&#xff0c;比如AndroidManifest.xml 文件 &#…

ASP.NET Core中Filter與Middleware的區別

中間件是ASP.NET Core這個基礎提供的功能&#xff0c;而Filter是ASP.NET Core MVC中提供的功能。ASP.NET Core MVC是由MVC中間件提供的框架&#xff0c;而Filter屬于MVC中間件提供的功能。 區別 中間件可以處理所有的請求&#xff0c;而Filter只能處理對控制器的請求&#x…

基礎篇05-圖像直方圖操作

本節將簡要介紹Halcon中有關圖像直方圖操作的算子&#xff0c;重點介紹直方圖獲取和顯示兩類算子&#xff0c;以及直方圖均衡化處理算子。 目錄 1. 引言 2. 獲取并顯示直方圖 2.1 獲取&#xff08;灰度&#xff09;直方圖 (1) gray_histo算子 (2) gray_histo_abs算子 (3…

MySQL | Navicat安裝教程

MySQL | Navicat安裝教程 &#x1fa84;個人博客&#xff1a;https://vite.xingji.fun 簡介 Navicat 是一款流行的 圖形化數據庫管理工具&#xff0c;由 PremiumSoft 公司開發&#xff0c;支持多種主流數據庫系統&#xff08;如 MySQL、MariaDB、SQL Server、Oracle、Postgre…

硬件實現I2C案例(寄存器實現)

一、需求分析 二、硬件電路設計 本次案例需求與前面軟件模擬案例一致&#xff0c;這里不再贅述&#xff0c;不清楚可參見下面文章&#xff1a;軟件模擬I2C案例&#xff08;寄存器實現&#xff09;-CSDN博客 值得注意的是&#xff0c;前面是軟件模擬I2C&#xff0c;所以并沒有…

基于SpringBoot養老院平臺系統功能實現六

一、前言介紹&#xff1a; 1.1 項目摘要 隨著全球人口老齡化的不斷加劇&#xff0c;養老服務需求日益增長。特別是在中國&#xff0c;隨著經濟的快速發展和人民生活水平的提高&#xff0c;老年人口數量不斷增加&#xff0c;對養老服務的質量和效率提出了更高的要求。傳統的養…

matlab simulink 汽車四分之一模型輪胎帶阻尼

1、內容簡介 略 matlab simulink121-汽車四分之一模型輪胎帶阻尼 可以交流、咨詢、答疑 2、內容說明 略 3、仿真分析 略 4、參考論文 略

w196Spring Boot高校教師科研管理系統設計與實現

&#x1f64a;作者簡介&#xff1a;多年一線開發工作經驗&#xff0c;原創團隊&#xff0c;分享技術代碼幫助學生學習&#xff0c;獨立完成自己的網站項目。 代碼可以查看文章末尾??聯系方式獲取&#xff0c;記得注明來意哦~&#x1f339;贈送計算機畢業設計600個選題excel文…

【鴻蒙開發】第二十四章 AI - Core Speech Kit(基礎語音服務)

目錄 1 簡介 1.1 場景介紹 1.2 約束與限制 2 文本轉語音 2.1 場景介紹 2.2 約束與限制 2.3 開發步驟 2.4 設置播報策略 2.4.1 設置單詞播報方式 2.4.2 設置數字播報策略 2.4.3 插入靜音停頓 2.4.4 指定漢字發音 2.5 開發實例 3 語音識別 3.1 場景介紹 3.2 約束…