C++(22)--繼承和派生

繼承和派生

  • 1.基本概念
  • 2.實現公有繼承
  • 3.私有繼承的例子
  • 4. 繼承和組合

《老九學堂C++課程》《C++ primer》學習筆記。《老九學堂C++課程》詳情請到B站搜索《老九零基礎學編程C++入門》
-------------簡單的事情重復做,重復的事情用心做,用心的事情堅持做(老九君)---------------

1.基本概念

面向對象oop–三大重要特性-- 封裝、繼承、多態

在C++中,代碼重用是通過“繼承(inheritance)”機制實現的。
在一個已經存在的類的基礎上,再建立一個新類。
從已有的類中派生出新類,派生類就繼承了原有類(基類)的特征,包括成員和方法(以后函數就叫方法)

通過繼承可以完成的功能-可升級可維護

  1. 在已有類的基礎上增加新的功能,對于數組類,可以添加數學計算–排序
  2. 給類添加數據成員,對于字符串類,可以派生類,并添加制定成員表示顏色。
  3. 修改類的方法,對于普通英雄,可以派生出擁有更豐富的技能的近戰英雄類

注意:
繼承機制只需要提供新的特性,甚至不需要訪問源碼就可以派生出類
允許在不公開的情況下將自己的類分發給他人,同時允許他們在類中添加新的特性。

程序升級和擴展–非常忌諱的是,修改原有的代碼。原來的代碼測試通過了,測試實際是一件非常困難的事。

開發一款RPG(Role-playing Gam)游戲
游戲職業:坦克,戰士,刺客,法師,射手,輔助

1.0 版本:戰士,法師
直接定義英雄類:戰士類,法師類–存在相同屬性和方法。
把相同的成員和方法封裝成基類。

注意:
1.派生類對象存儲了基類的數據成員
2.派生類對象可以調用基類的非私有函數
3.派生類需要自己的構造方法
4.派生類根據需要增加額外的成員和方法

繼承的繼承:稱為直接基類和間接基類。

父類的的成員和方法的公有,私有,和受保護三種屬性的訪問權限:
1.公有權限下,自己和派生類,以及外部都能訪問
2.私有權限下,只有自己訪問,派生類和外部都無法訪問
3.受保護權限下,自己和派生類可以訪問,外部無法訪問
繼承分為公有繼承,私有繼承,受保護繼承。三種方式繼承之后子類權限的變化

基類成員公有繼承私有繼承保護繼承
公有公有私有受保護
受保護受保護私有受保護
私有不被繼承不被繼承不被繼承

全部繼承,不封裝基類–公有繼承(除了基類的私有成員不繼承,其他都是權限不變的繼承)is a 關系。
全部繼承,完全封裝基類–私有繼承(庶出,除了基類的私有成員不繼承,其他成員繼承后權限改成私有) has a關系。使用包含來實現has a ,用繼承來實現有點抽象。
全部繼承,有選擇封裝基類–受保護(除了基類的私有成員不繼承,其他成員繼承后權限被改為受保護模式)

靈活運用面向對象思想的重要體現。
不管使用哪一種繼承,派生類都不能訪問基類里的私有成員,除非改成protected.

class Emperor
{
private:string[] bueaties; // 后宮佳麗double silvers;    // 私房錢
protected:string palace; 	   // 宮殿名稱
publicEmperor();~Emperor();string reignTile; 	// 年號
}
// 子類的繼承關系,非實際代碼
class FourthSon:public Emperor
{
// 父類私有成員不可見,
protected:string palace; 		//宮殿名稱
public:FourthSon();~FourthSon();string reignTile;  	// 年號
}
class ThirteenSon:protected Emperor
{
protected: // 外人訪問不了,只有自己,友元,以及子類能夠訪問。string reignTile; 	// 年號string palace; 		// 宮殿名稱
public:ThirteenSon();~ThirteenSon();
}
class SecondSon: private Emperor
{
private:    //僅作說明,只有自己訪問string palace;		//宮殿名稱string reignTile; 	// 年號
piblic:SecondSon();~SecondSon();
}

2.實現公有繼承

掌握公有繼承,了解私有繼承和受保護繼承。
滿足is a 關系的可以用繼承。
clion 還不會寫配置文件,類圖生成

類對象在內存中的存儲情況

  1. 在沒有繼承關系時的內存模型
    a)對象的成員變量存在堆內存區/棧內存區,代碼存儲在公有的成員函數代碼區。所有的對象共同享有一段函數代碼
    b)如果使用sizeof 求類所占空間的大小,只是計算了成員變量的大小,并沒有把成員函數也包含在內。
  2. 有繼承關系時的內存模型
    a)派生類的內存模型看成是基類成員變量和新增成員變量的總和,所有的成員函數仍然共有另一個區域–代碼區。

創建的時候先初始化基類再初始化派生類
釋放時先釋放派生類再釋放基類

demo1: Warrior 公有繼承

//main.cpp
#include <iostream>
#include <string>
#include "Hero.h"
#include "Warrior.h"using namespace std;
void HeroTest();
void WarriorTest();
int main()
{// HeroTest();WarriorTest();
}
void HeroTest()
{Hero hero1;cout << hero1 << endl;hero1.Move();Hero * hero2 = new Hero("測試英雄2",999,5000,5000);cout << *hero2 << endl;hero2->Move();//(*hero2).Move();      // 等價調用
}
void WarriorTest(){Warrior warrior1;// 情況1:派生類中沒有重新實現move方法,調用父類方法// 情況2:派生類中重新實現move方法,調用子類實現的該方法warrior1.Move();cout << warrior1 << endl;Hero * hero = new Warrior;  // 基類指針指向了派生類--標準的多態hero->Move();               // 調用基類的實現delete hero;}
//Hero.h
//
// Created by 陳瑩瑩 on 2021/3/15.
//#ifndef CHAPTER13_1_HERO_H
#define CHAPTER13_1_HERO_H#include <string>
#include <vector>
#include <list>
#include <iostream>
#include <assert.h>
using namespace std;
class Hero
{
private:string m_NickName;int m_Level;int m_MaxLife;int m_CurrLife;int x;int y;public:Hero();Hero(const string& nickName);Hero(const string& nickName, int level);Hero(const string& nickName, int level, int maxLife, int currLife);void Move();friend ostream& operator<<(ostream& out, const Hero& hero);// friend ostream& operator<<(ostream& out, const* hero);string GetNickName() const{return m_NickName;}int GetLevel() const{return m_Level;}int GetMaxLife() const{return m_MaxLife;}int GetCurrLife() const{return m_CurrLife;}void SetNickName(const string & nickName){this->m_NickName = nickName;}void SetLevel(int level);void SetMaxLife(int maxLife);void SetCurrLife(int currLife);void operation1();
};
#endif //CHAPTER13_1_HERO_H
//Hero.cpp
//
// Created by 陳瑩瑩 on 2021/3/15.
//#include "Hero.h"
#include <string>
#include <vector>
#include <list>
#include <iostream>
#include <assert.h>
#include "Hero.h"
using namespace std;Hero::Hero() : m_NickName("默認英雄"),m_Level(1),m_MaxLife(100),m_CurrLife(100)
{cout << "調用了Hero的默認構造" << endl;
}
//Hero::Hero(const string& nickName):m_NickName(nickName),m_Level(1),m_MaxLife(100),m_CurrLife(100)
//{
//
//}
Hero::Hero(const string& nickName):Hero(nickName,1,100,10)
{cout << "調用了Hero 一個參數版本的構造" << endl;
}
Hero::Hero(const string& nickName, int level):Hero(nickName, level,100,10)
{cout << "調用了Hero 兩個參數版本的構造" << endl;
}
Hero::Hero(const string& nickName, int level, int maxLife, int currLife):m_NickName(nickName),m_Level(level),m_MaxLife(maxLife),m_CurrLife(currLife)
{cout << "調用了Hero 四個參數版本的構造" << endl;
}
void Hero::Move()
{// 默認移動cout << "普通英雄" << m_NickName << "正在奔跑在艾澤拉斯大陸上" << endl;
}
ostream& operator<<(ostream& out, const Hero& hero){out << "昵稱:" << hero.GetNickName() << "\n";out << "等級:" << hero.GetLevel() << "\n";out << "最大生命:" << hero.GetMaxLife() << "\n";out << "當前生命:" << hero.GetCurrLife() ;return out;
}
void Hero::operation1()
{
}
//Warrior.h
//
// Created by 陳瑩瑩 on 2021/3/16.
//
#ifndef CHAPTER13_1_WARRIOR_H
#define CHAPTER13_1_WARRIOR_H
#include "Hero.h"
// 共有繼承-體現了is a 關系
class Warrior : public Hero{
private:int m_PhysicalAttack;
public:Warrior();Warrior(const string& nickName, int phyAttack);void Move();  // 在派生類中實現派生類版本的move方法~Warrior();
};
#endif //CHAPTER13_1_WARRIOR_H
//Warrior.cpp
//
// Created by 陳瑩瑩 on 2021/3/16.
//
#include "Warrior.h"
Warrior::Warrior() :Hero("默認構造",1,100,100)
{
}
Warrior::Warrior(const string& nickName, int phyAttack):Hero(nickName,1,100,100),m_PhysicalAttack(phyAttack)
{
}
void Warrior::Move()
{// m_NickName沒辦法過呀,不能訪父類的私有屬性,需要在將父類中私有成員改為受保護成員//cout << "戰士《" << m_NickName << "》"<< "背著一大堆近戰武器正在前進。。。"<< endl;cout << "戰士《" << GetNickName() << "》"<< "背著一大堆近戰武器正在前進。。。"<< endl;
}
Warrior::~Warrior()
{
}

有關基類,派生類構造

  1. 實例化派生類對象時,首先會創建基類對象(調用基類構造)
  2. 派生類構造應通過成員初始化列表將基類信息傳遞給基類構造
  3. 應該在派生類構造中初始化派生類新增的數據成員

派生類與基類之間特殊關系小結
1.派生類可以使用基類的非私有成員函數(public和protect)

2.基類指針可以在不進行顯示類型轉換的情況下指向派生類對象

Warrior warrior1("諸葛達摩", 10, 100, 100);
Hero& refHero = warrior1; // 基類引用指向派生類,
Hero* ptrHero = &warrior1; // 基類指針指向派生類對象
Warrior& warrior2 = (Warrior)refHero;  // 父類引用/指針需要強制轉換成子類引用/指針(前提:父類指針指向子類對象)
//不可以將基類對象的地址賦給派生類引用和對象,即不能進行逆操作

3.可以將派生類對象賦值給基類對象,程序會使用隱式重載賦值運算符

Hero hero = warrior;
hero.move();   //調用父類方法

3.私有繼承的例子

沒講完呀,暫且收一收好了

//main.cpp
#include <iostream>
#include "Teacher.h"
void TeacherTest(){Teacher teacher1(8000);// 名字設置沒有寫完
}
int main()
{TeacherTest();return 0;
}
//Teacher.h
//
// Created by 陳瑩瑩 on 2021/3/21.
//#ifndef CHAPTER13_1_TEACHER_H
#define CHAPTER13_1_TEACHER_H
#include <iostream>
#include <string>
using namespace std;
/** 用來演示私有繼承的其中一種用法* 實現組合關系,只能組合一個屬性不能組合兩個屬性* Teacher類中擁有string類型的成員name* */class Teacher :private string{    // teacher 中擁有string類型的成員
private:double salary;                // 工資public:Teacher();Teacher(int _salary) : salary(_salary){}double GetSalary(){return salary;}void SetSalary(double salary){this->salary = salary;}// 難點const string& GetName() const{/** Teacher類是由string 類私有派生而來,所以,可以使用強制類型轉換,將Teacher類轉換成string類* 為了避免調用構造函數創建新的對象,所以強制轉換成了string 的引用類型返回* 本方法返回一引用,指向調用本方法的Teacher 對象中繼承而來的string對象* */return (const string&)*this;      //強轉}//using string::length();   //將字符串方法聲明為本類的公有方法/*返回當前教師類對象姓名的字符串長度*/int GetLenght(){return string::length();}~Teacher();string nickName;             // 使用組合關系實現比較簡單的has-a 關系protected:};
#endif //CHAPTER13_1_TEACHER_H

4. 繼承和組合

一張臉由多個類組合而成,頭發的不同總類從父類頭發那里繼承而來。

繼承是is a 縱向關系–狗是哺乳動物,戰士是英雄,橘貓是寵物–
組合是has a 橫向關系–學生有書包,戰士有武器,

繼承是C++與C最重要的區別,雖然C++也可以用C語言的編程習慣。

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

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

相關文章

Python- 解決PIP下載安裝速度慢

對于Python開發用戶來講&#xff0c;PIP安裝軟件包是家常便飯。但國外的源下載速度實在太慢&#xff0c;浪費時間。而且經常出現下載后安裝出錯問題。所以把PIP安裝源替換成國內鏡像&#xff0c;可以大幅提升下載速度&#xff0c;還可以提高安裝成功率。 國內源&#xff1a; …

leetcode102 二叉樹的層次遍歷

給定一個二叉樹&#xff0c;返回其按層次遍歷的節點值。 &#xff08;即逐層地&#xff0c;從左到右訪問所有節點&#xff09;。 例如: 給定二叉樹: [3,9,20,null,null,15,7], 3 / \ 9 20 / \ 15 7 返回其層次遍歷結果&#xff1a; [ [3], [9,20], [15…

Windows Git客戶端搭建

最近開始做Windows 開發&#xff0c;所以找了一些windows下安裝git的教程 本文環境&#xff1a; 操作系統&#xff1a;Windows XP SP3 Git客戶端&#xff1a;TortoiseGit-1.8.16.0-32bit 一、安裝Git客戶端 全部安裝均采用默認&#xff01; 1. 安裝支撐軟件 msysgit: http://ms…

C++(23)--多態性與虛函數

多態性與虛函數1.靜態多態-重載2.動態多態-重寫2.1 向上轉換/向下轉換3.虛函數的工作原理4.純虛函數和抽象類5.補充項目(都市浮生記)-卒《老九學堂C課程》學習筆記。《老九學堂C課程》詳情請到B站搜索《老九零基礎學編程C入門》-------------簡單的事情重復做&#xff0c;重復的…

如何在Appscale下發布自己的應用(一)

本篇文章主要講如何在本地搭建appscale環境。由于國內的信息資源有限&#xff0c;很多重要的論壇被墻了&#xff0c;所以遇到不少麻煩&#xff0c;由于最近一段時間vpn也被封掉了&#xff0c;我只能通過特殊渠道方法來翻墻查閱資料&#xff0c;走了不少彎路。 1.先說系統和環境…

總結了線程安全性的二十四個精華問題

1、對象的狀態&#xff1a;對象的狀態是指存儲在狀態變量中的數據&#xff0c;對象的狀態可能包括其他依賴對象的域。在對象的狀態中包含了任何可能影響其外部可見行為的數據。 2、一個對象是否是線程安全的&#xff0c;取決于它是否被多個線程訪問。這指的是在程序中訪問對象的…

如何在Appscale下發布自己的應用(二)

本文開始講如何發布自己的app應用到appscle上 建好appscle網站后&#xff0c;可以在命令行通過 appscle deploy apppathname 來發布自己應用。 除了用命令行提交應用之外&#xff0c;還可以通過appscale的網站直接提交&#xff0c;選擇 upload application->選擇上傳文件-&g…

Python模塊(7)-SciPy 簡易使用教程

SciPy 簡易使用教程1. 符號計算2. 函數向量化3. 波形處理scipy.signal3.1 濾波器3.2 波峰定位基于numpy的一個高級模塊&#xff0c;為數學&#xff0c;物理&#xff0c;工程等方面的科學計算提供無可替代的支持。 做重要的思想是&#xff1a;符號計算和函數向量化 1. 符號計算…

Xcode的Architectures和Valid Architectures的區別

目錄[-] Xcode的Architectures和Valid Architectures的區別 Architectures Valid Architectures 原因解釋如下&#xff1a; 參考1&#xff1a; 所有IOS設備詳情列表 List of iOS devices - Wikipedia, the free encyclopedia 參考2&#xff1a; iOS 7: 如何為iPhone 5S編譯64位…

Python模塊(8)-sklearn 簡易使用教程

sklearn 簡易使用教程1.scikit-learn的數據集2.scikit-learn 的訓練和預測scikit-learn 是在Numpy,SciPy,Matplotlib三個模塊上編寫的&#xff0c;數據挖掘和數據分析的一個簡單有效的工具。scikit-learn包括6大功能&#xff1a;分類&#xff0c;回歸&#xff0c;聚類&#xff…

如何發布GAE的應用(一)

安裝googleSDK的環境&#xff1a; 1 下載安裝包從官網下載 https://cloud.google.com/sdk/downloads -> https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-sdk-170.0.0-windows-x86_64-bundled-python.zip 2 如果本地安裝了python&#xff0c;直…

leetcode887 雞蛋掉落

你將獲得 K 個雞蛋&#xff0c;并可以使用一棟從 1 到 N 共有 N 層樓的建筑。 每個蛋的功能都是一樣的&#xff0c;如果一個蛋碎了&#xff0c;你就不能再把它掉下去。 你知道存在樓層 F &#xff0c;滿足 0 < F < N 任何從高于 F 的樓層落下的雞蛋都會碎&#xff0c;…

Docker 的日志相關整理

1 Docker daemon日志的位置 Docker daemon日志的位置&#xff0c;根據系統不同各不相同。 Ubuntu - /var/log/upstart/docker.logBoot2Docker - /var/log/docker.logDebian GNU/Linux - /var/log/daemon.logCentOS - /var/log/daemon.log | grep dockerFedora - journalctl -u…

PaperNotes(15)-圖神經網絡、PyG極簡版入門筆記

圖神經網絡概況1.GNN,GCN,GE的區別2.圖卷積的通式--矩陣該如何作用2.1實現12.2實現22.3實現33.PyTorch geometric3.1 PyG內置數據集3.1.1ENZYMES dataset3.1.2Cora3.2 PyG自定義數據集3.2.1Data構建簡單的圖結構3.2.2 Dataset3.2.3 InMemoryDataset一文讀懂圖卷積GCN(https://z…

leetcode76 最小覆蓋子串

給你一個字符串 S、一個字符串 T&#xff0c;請在字符串 S 里面找出&#xff1a;包含 T 所有字母的最小子串。 示例&#xff1a; 輸入: S "ADOBECODEBANC", T "ABC" 輸出: "BANC" 說明&#xff1a; 如果 S 中不存這樣的子串&#xff0c;則返…

Unity的匹配系統

這個匹配系統是指一個玩家&#xff0c;可以創建一個自己隨意命名的房間&#xff0c;然后其他玩家可以通過聯網去搜索房間&#xff0c;然后加入房間一起游戲 我先講講怎么使用這個匹配系統&#xff1a; 在運行游戲后&#xff0c;因為添加了Network Manager HUD組件&#xff0c;所…

PaperNotes(16)-圖神經網絡GNN簡史、不動點建模-筆記

圖神經網絡簡史、簡介1.圖神經網絡簡史2.圖神經網絡--學習過程3.圖神經網絡--理論基礎4.圖神經網絡的局限5.GNN,RNN,GGNN6.小結閱讀筆記&#xff1a;從圖(Graph)到圖卷積(Graph Convolution)&#xff1a;漫談圖神經網絡模型 (一)(https://www.cnblogs.com/SivilTaram/p/graph_n…

Matchmaker

Unity的多玩家網絡功能包含了玩家在因特網上互相玩而不需要公共IP地址的服務。用戶可以創建游戲,獲取活動游戲列表;加入并退出游戲。當在internet上玩時,網絡流量將通過云中的Unity,而不是直接在客戶端之間進行。這就避免了防火墻和NATs的問題,幾乎可以在任何地方玩游戲。 …

PaperNotes(17)-圖卷積神經網絡GCN-筆記

圖卷積神經網絡GCN-筆記1.卷積是什么2.圖卷積的源起3.空域卷積3.1消息傳遞網絡MPNN3.2 圖采樣與聚合GraphSage4.頻域卷積5.圖結構的序列化-Patch-SAN從圖(Graph)到圖卷積(Graph Convolution)&#xff1a;漫談圖神經網絡模型 (二)(https://www.cnblogs.com/SivilTaram/p/graph_n…

Servlet 工程 web.xml 中的 servlet 和 servlet-mapping 標簽

摘錄某個工程的 web.xml 文件片段&#xff1a;訪問順序為1—>2—>3—>4&#xff0c;其中2和3的值必須相同。 url-pattern 標簽中的值是要在瀏覽器地址欄中輸入的 url&#xff0c;可以自己命名&#xff0c;這個 url 訪問名為 servlet-name 中值的 servlet&#xff0c;兩…