【C++】詳細講解繼承(下)

? ? ? ? 本篇來繼續說說繼承。上篇可移步至【C++】詳細講解繼承(上)?

1.繼承與友元

友元關系不能繼承 ,也就是說基類友元不能訪問派?類私有和保護成員。
class Student;//前置聲明class Same //基類
{
public:friend void Fun(const Same& p, const Student& s);//友元聲明
protected:string _name; 
};class Student : public Same //派生類
{
protected:int _stuid;
};
void Fun(const Same& p, const Student& s)
{cout << p._name << endl;cout << s._stuid << endl;
}

像上面的代碼,Fun函數只能訪問Same基類的成員變量_name,_stuid是訪問不到的。

?解決方法就是在派生類Student里面也加上友元聲明,就可以了。

class Student : public Same //派生類
{friend void Fun(const Same& p, const Student& s);//友元聲明
protected:int _stuid;
};

2.繼承與靜態成員

基類定義了static靜態成員,則整個繼承體系?? 只有?個這樣的成員 。?論派?出多少個派?類,都只有?個static成員實例。
class Same //基類
{
public:string _name;static int _count;//靜態成員變量
};int Same::_count = 0;//靜態成員變量初始化class Student : public Same //派生類
{
protected:int _stuNum;
};

?我們觀察一下_name的地址和_count的地址。

int main()
{Same p;Student s;cout << &p._name << endl;cout << &s._name << endl;cout << &p._count << endl;cout << &s._count << endl;return 0;
}

這?的運?結果可以看到:?靜態成員_name的地址是不?樣的,說明派?類繼承下來了,基類和派?類對象各有?份靜態成員_count的地址是?樣的,說明派?類和基類共?同?份靜態成員。

公有情況下,基類和派生類指定類域都可以訪問靜態成員變量。

cout << Same::_count << endl;
cout << Student::_count << endl;

也可以通過對象訪問。

?

?改變其中一個,另一個也改變,因為這就是同一個。

cout << Same::_count << endl;
cout << Student::_count << endl;
Same::_count++; //改變_count
cout << p._count << endl;
cout << s._count << endl;

3.多繼承以及菱形繼承

3.1 繼承模型

  • 單繼承:?個派?類只有?個直接基類時稱這個繼承關系為單繼承
  • 多繼承:?個派?類有兩個或以上直接基類時稱這個繼承關系為多繼承,多繼承對象在內存中的模型是,先繼承的基類在前?,后?繼承的基類在后?,派?類成員在放到最后?。
  • 菱形繼承:菱形繼承是多繼承的?種特殊情況,如下。

菱形繼承有數據冗余?義性(存在歧義)的問題,在Assistant的對象中Person成員會有兩份。所以在實踐中并不提倡設計出菱形繼承的模型。

?二義性問題可以通過指定訪問哪個基類的成員來解決,但是數據冗余問題是不能得到解決的。

如果在特定場景下,一定需要設計菱形繼承,怎么辦?虛繼承就出場了。

3.2 虛繼承

新增了一個關鍵字virtual。放在會造成數據冗余和二義性的那些類上

這里就是在Student和Teacher 加上virtual,都要加,只加一個都沒用。

class Person
{
public:string _name; // 姓名};
// 使?虛繼承Person類
class Student : virtual public Person
{
protected:int _num; //學號
};
// 使?虛繼承Person類
class Teacher : virtual public Person
{
protected:int _id; // 職?編號
};class Assistant : public Student, public Teacher
{
protected:string _majorCourse; // 主修課程
};

?加了virtual后person在Assistant里繼承的數據就只有一份了,數據冗余和二義性就得到了解決。

3.3 相關小測試

假如現在有一個菱形繼承關系如下,?virtual應該加在哪里?

加在B類和C類上。因為E里面會有數據冗余和二義性,而這些冗余的數據是因為A有兩份,導致繼承A的是B和C,所以要加在B和C上,不是D和C。

?最后,除非萬不得已,不要設計出菱形繼承。菱形繼承以及virtual的底層是特別復雜的。

3.4 多繼承中指針偏移問題

先看題。

class Base1 { public: int _b1; };
class Base2 { public: int _b2; };
class Derive : public Base1, public Base2 { public: int _d; };
int main()
{Derive d;Base1* p1 = &d;Base2* p2 = &d;Derive* p3 = &d;return 0;
}

說法正確的是?

A :p1 == p2 == p3? ? B :p1 < p2 < p3? ? C :p1 == p3 != p2? ? D :p1 != p2 != p3
答案?C :p1 == p3 != p2?
先繼承的在前面 ,先聲明的在前面,所以Base1和Base2的底層位置如下。
p3是Derive的指針,指向開頭。
p1是Base1的指針,Base1是基類,p1指向的范圍是派生類Derive切出來的Base1的那部分,最開始指向開頭,和p3一個位置。
p2與p1同理,指向的范圍是Derive切出來的Base2的那部分,最開始指向Base2開頭。
所以答案是 p1 == p3 != p2?
借上面那個題,說了多繼承中的指針偏移問題。

4.繼承和組合

  • public繼承是?種is-a的關系。也就是說每個派?類對象都?個基類對象。
  • 組合是?種has-a的關系。假設B組合了A,每個B對象中都?個A對象。
  • 繼承允許你根據基類的實現來定義派?類的實現。這種通過?成派?類的復?通常被稱為?箱復?(white-box reuse)。在繼承?式中,基類的內部細節對派?類可? 。繼承?定程度破壞了基類的封裝,基類的改變,對派?類有很?的影響。派?類和基類間的依賴關系很強,耦合度?
  • 對象組合是類繼承之外的另?種復?選擇。新的更復雜的功能可以通過組裝或組合對象來獲得。對象組合要求被組合的對象具有良好定義的接?。這種復??格被稱為?箱復?(black-box reuse),因為對象的內部細節是不可?的。對象只以“?箱”的形式出現。 組合類之間沒有很強的依賴關系,耦合度低
  • 優先使?組合,?不是繼承。實際盡量多去?組合,組合的耦合度低,代碼維護性好,但這也不是絕對的,要根據實際選擇使用。

比如下面的代碼,就能很好解釋繼承和組合。

class Tire //輪胎
{
protected:string _brand; // 品牌size_t _size; // 尺?
};
class Car //車
{
protected:string _colour; // 顏?string _num; // ?牌號Tire _t1; // 輪胎Tire _t2; // 輪胎Tire _t3; // 輪胎Tire _t4; // 輪胎
};

輪胎和車就比較符合 has-a 的關系,車輪胎,用的組合

class BMW : public Car //繼承
{
public:void Drive() { cout << "BMW" << endl; }
};class Benz : public Car //繼承
{
public:void Drive() { cout << "Benz" << endl; }
};

上面的代碼是繼承,BMW 和?Benz 是品牌,比較符合 is-a 的關系,BMW和Benz車。

本次分享就到這里了,我們下篇見~

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

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

相關文章

考研機試題:今年的第幾天

描述 輸入年、月、日&#xff0c;計算該天是本年的第幾天。 輸入描述: 包括三個整數年(1<Y<3000)、月(1<M<12)、日(1<D<31)。 輸出描述: 輸入可能有多組測試數據&#xff0c;對于每一組測試數據&#xff0c; 輸出一個整數&#xff0c;代表Input中的年、…

解鎖羅技鍵盤新技能:輕松鎖定功能鍵(羅技K580)

在使用羅技鍵盤的過程中&#xff0c;你是否曾因 F11、F12 功能鍵的默認設置與實際需求不符而感到困擾&#xff1f; 別擔心&#xff0c;今天就為大家分享一個簡單實用的小技巧 —— 鎖定羅技鍵盤的 F11、F12 功能鍵&#xff0c;讓你的操作更加得心應手&#xff01; 通常情況下…

Flink把kafa數據寫入Doris的N種方法及對比。

用Flink+Doris來開發實時數倉,首要解決是如何接入kafka實時流,下面是參考Doris官方文檔和代碼,在自己項目開發的實踐中總結,包括一些容易踩坑的細節。 目錄 Routine Load方法 接入kafka實時數據 踩坑的問題細節 Flink Doris Connector方法 完整示例 Routine Load方法…

小識JVM堆內存管理的優化機制TLAB

JVM&#xff08;Java虛擬機&#xff09;在堆內存分配空間時&#xff0c;TLAB&#xff08;Thread Local Allocation Buffer&#xff0c;線程本地分配緩存區&#xff09;是一種重要的內存管理優化技術。以下是對TLAB的詳細解釋&#xff1a; 一、TLAB的定義 TLAB是JVM堆內存管理…

(開源)基于Django+Yolov8+Tensorflow的智能鳥類識別平臺

1 項目簡介&#xff08;開源地址在文章結尾&#xff09; 系統旨在為了幫助鳥類愛好者、學者、動物保護協會等群體更好的了解和保護鳥類動物。用戶群體可以通過平臺采集野外鳥類的保護動物照片和視頻&#xff0c;甄別分類、實況分析鳥類保護動物&#xff0c;與全世界各地的用戶&…

【力扣Hot 100】普通數組2

3. 輪轉數組 給定一個整數數組 nums&#xff0c;將數組中的元素向右輪轉 k **個位置&#xff0c;其中 k **是非負數。 示例 1: 輸入: nums [1,2,3,4,5,6,7], k 3 輸出:[5,6,7,1,2,3,4]解釋: 向右輪轉 1 步:[7,1,2,3,4,5,6] 向右輪轉 2 步:[6,7,1,2,3,4,5] 向右輪轉 3 步:[…

專題三_窮舉vs暴搜vs深搜vs回溯vs剪枝_全排列

dfs解決 全排列&子集 1.全排列 link:46. 全排列 - 力扣&#xff08;LeetCode&#xff09; 全局變量回溯 code class Solution { public:vector<vector<int>> ans;vector<int> cur;vector<bool> used;vector<vector<int>> permute…

2_高并發內存池_各層級的框架設計及ThreadCache(線程緩存)申請內存設計

一、高并發內存池框架設計 高并發池框架設計&#xff0c;特別是針對內存池的設計&#xff0c;需要充分考慮多線程環境下&#xff1a; 性能問題鎖競爭問題內存碎片問題 高并發內存池的整體框架設計旨在提高內存的申請和釋放效率&#xff0c;減少鎖競爭和內存碎片。 高并發內存…

JAVA 使用反射比較對象屬性的變化,記錄修改日志。使用注解【策略模式】,來進行不同屬性枚舉值到中英文描述的切換,支持前端國際化。

1.首先定義一個接口&#xff0c;接口中有兩個方法&#xff0c;分別是將屬性轉換成英文描述和中文描述。 其實就是將數據庫中記錄的 0 1 &#xff0c;轉換成后面的描述 這邊定義了中文轉換為默認方法&#xff0c;是因為有些屬性不需要進行中文轉換&#xff0c;或者該屬性的枚舉…

webrtc入門系列(五)amazon-kinesis-video-streams-webrtc-sdk-c編譯

《webrtc入門系列&#xff08;一&#xff09;easy_webrtc_server 入門環境搭建》 《webrtc入門系列&#xff08;二&#xff09;easy_webrtc_server 入門example測試》 《webrtc入門系列&#xff08;三&#xff09;云服務器coturn環境搭建》 《webrtc入門系列&#xff08;四&…

AIGC大模型詳解(ChatGPT,Cursor,豆包,文心一格)

定義與概念 AIGC&#xff08;AI Generated Content&#xff09;大模型是基于人工智能技術&#xff0c;具有海量參數、強大算力支持&#xff0c;能處理和生成多種類型內容的深度學習模型。可自主學習數據中的模式和規律&#xff0c;生成文本、圖像、音頻等內容&#xff0c;如Ch…

.NET9增強OpenAPI規范,不再內置swagger

ASP.NETCore in .NET 9.0 OpenAPI官方文檔ASP.NET Core API 應用中的 OpenAPI 支持概述 | Microsoft Learnhttps://learn.microsoft.com/zh-cn/aspnet/core/fundamentals/openapi/overview?viewaspnetcore-9.0https://learn.microsoft.com/zh-cn/aspnet/core/fundamentals/ope…

第38周:貓狗識別 (Tensorflow實戰第八周)

目錄 前言 一、前期工作 1.1 設置GPU 1.2 導入數據 輸出 二、數據預處理 2.1 加載數據 2.2 再次檢查數據 2.3 配置數據集 2.4 可視化數據 三、構建VGG-16網絡 3.1 VGG-16網絡介紹 3.2 搭建VGG-16模型 四、編譯 五、訓練模型 六、模型評估 七、預測 總結 前言…

我的2024年年度總結

序言 在前不久&#xff08;應該是上周&#xff09;的博客之星入圍賽中鎩羽而歸了。雖然心中頗為不甘&#xff0c;覺得這一年兢兢業業&#xff0c;每天都在發文章&#xff0c;不應該是這樣的結果&#xff08;連前300名都進不了&#xff09;。但人不能總抱怨&#xff0c;總要向前…

Trimble三維激光掃描-地下公共設施維護的新途徑【滬敖3D】

三維激光掃描技術生成了復雜隧道網絡的高度詳細的三維模型 項目背景 紐約州北部的地下通道網絡已有100年歷史&#xff0c;其中包含供暖系統、電線和其他公用設施&#xff0c;現在已經開始顯露出老化跡象。由于安全原因&#xff0c;第三方的進入受到限制&#xff0c;在沒有現成紙…

QT 中 UDP 的使用

目錄 一、UDP 簡介 二、QT 中 UDP 編程的基本步驟 &#xff08;一&#xff09;包含頭文件 &#xff08;二&#xff09;創建 UDP 套接字對象 &#xff08;三&#xff09;綁定端口 &#xff08;四&#xff09;發送數據 &#xff08;五&#xff09;接收數據 三、完整示例代…

開源鴻蒙開發者社區記錄

lava鴻蒙社區可提問 Laval社區 開源鴻蒙項目 OpenHarmony 開源鴻蒙開發者論壇 OpenHarmony 開源鴻蒙開發者論壇

Git上傳了秘鑰如何徹底修改包括歷史記錄【從安裝到實戰詳細版】

使用 BFG Repo-Cleaner 清除 Git 倉庫中的敏感信息 1. 背景介紹 在使用 Git 進行版本控制時&#xff0c;有時會不小心將敏感信息&#xff08;如 API 密鑰、密碼等&#xff09;提交到倉庫中。即使后續刪除&#xff0c;這些信息仍然存在于 Git 的歷史記錄中。本文將介紹如何使用…

多層 RNN原理以及實現

數學原理 多層 RNN 的核心思想是堆疊多個 RNN 層&#xff0c;每一層的輸出作為下一層的輸入&#xff0c;從而逐層提取更高層次的抽象特征。 1. 單層 RNN 的數學表示 首先&#xff0c;單層 RNN 的計算過程如下。對于一個時間步 t t t&#xff0c;單層 RNN 的隱藏狀態 h t h_t…

RNA 測序技術概覽(RNA-seq)

前言 轉錄組測序&#xff08;RNA-seq&#xff09;是當下最流行的二代測序&#xff08;NGS&#xff09;方法之一&#xff0c;使科研工作者實現在轉錄水平上定量、定性的研究&#xff0c;它的出現已經革命性地改變了人們研究基因表達調控的方式。然而&#xff0c;轉錄組測序&…