C++(22)--继承和派生
繼承和派生
- 1.基本概念
- 2.實(shí)現(xiàn)公有繼承
- 3.私有繼承的例子
- 4. 繼承和組合
《老九學(xué)堂C++課程》《C++ primer》學(xué)習(xí)筆記。《老九學(xué)堂C++課程》詳情請(qǐng)到B站搜索《老九零基礎(chǔ)學(xué)編程C++入門(mén)》
-------------簡(jiǎn)單的事情重復(fù)做,重復(fù)的事情用心做,用心的事情堅(jiān)持做(老九君)---------------
1.基本概念
面向?qū)ο髈op–三大重要特性-- 封裝、繼承、多態(tài)
在C++中,代碼重用是通過(guò)“繼承(inheritance)”機(jī)制實(shí)現(xiàn)的。
在一個(gè)已經(jīng)存在的類(lèi)的基礎(chǔ)上,再建立一個(gè)新類(lèi)。
從已有的類(lèi)中派生出新類(lèi),派生類(lèi)就繼承了原有類(lèi)(基類(lèi))的特征,包括成員和方法(以后函數(shù)就叫方法)
通過(guò)繼承可以完成的功能-可升級(jí)可維護(hù)
注意:
繼承機(jī)制只需要提供新的特性,甚至不需要訪問(wèn)源碼就可以派生出類(lèi)
允許在不公開(kāi)的情況下將自己的類(lèi)分發(fā)給他人,同時(shí)允許他們?cè)陬?lèi)中添加新的特性。
程序升級(jí)和擴(kuò)展–非常忌諱的是,修改原有的代碼。原來(lái)的代碼測(cè)試通過(guò)了,測(cè)試實(shí)際是一件非常困難的事。
開(kāi)發(fā)一款RPG(Role-playing Gam)游戲
游戲職業(yè):坦克,戰(zhàn)士,刺客,法師,射手,輔助
1.0 版本:戰(zhàn)士,法師
直接定義英雄類(lèi):戰(zhàn)士類(lèi),法師類(lèi)–存在相同屬性和方法。
把相同的成員和方法封裝成基類(lèi)。
注意:
1.派生類(lèi)對(duì)象存儲(chǔ)了基類(lèi)的數(shù)據(jù)成員
2.派生類(lèi)對(duì)象可以調(diào)用基類(lèi)的非私有函數(shù)
3.派生類(lèi)需要自己的構(gòu)造方法
4.派生類(lèi)根據(jù)需要增加額外的成員和方法
繼承的繼承:稱(chēng)為直接基類(lèi)和間接基類(lèi)。
父類(lèi)的的成員和方法的公有,私有,和受保護(hù)三種屬性的訪問(wèn)權(quán)限:
1.公有權(quán)限下,自己和派生類(lèi),以及外部都能訪問(wèn)
2.私有權(quán)限下,只有自己訪問(wèn),派生類(lèi)和外部都無(wú)法訪問(wèn)
3.受保護(hù)權(quán)限下,自己和派生類(lèi)可以訪問(wèn),外部無(wú)法訪問(wèn)
繼承分為公有繼承,私有繼承,受保護(hù)繼承。三種方式繼承之后子類(lèi)權(quán)限的變化
| 公有 | 公有 | 私有 | 受保護(hù) |
| 受保護(hù) | 受保護(hù) | 私有 | 受保護(hù) |
| 私有 | 不被繼承 | 不被繼承 | 不被繼承 |
全部繼承,不封裝基類(lèi)–公有繼承(除了基類(lèi)的私有成員不繼承,其他都是權(quán)限不變的繼承)is a 關(guān)系。
全部繼承,完全封裝基類(lèi)–私有繼承(庶出,除了基類(lèi)的私有成員不繼承,其他成員繼承后權(quán)限改成私有) has a關(guān)系。使用包含來(lái)實(shí)現(xiàn)has a ,用繼承來(lái)實(shí)現(xiàn)有點(diǎn)抽象。
全部繼承,有選擇封裝基類(lèi)–受保護(hù)(除了基類(lèi)的私有成員不繼承,其他成員繼承后權(quán)限被改為受保護(hù)模式)
靈活運(yùn)用面向?qū)ο笏枷氲闹匾w現(xiàn)。
不管使用哪一種繼承,派生類(lèi)都不能訪問(wèn)基類(lèi)里的私有成員,除非改成protected.
2.實(shí)現(xiàn)公有繼承
掌握公有繼承,了解私有繼承和受保護(hù)繼承。
滿足is a 關(guān)系的可以用繼承。
clion 還不會(huì)寫(xiě)配置文件,類(lèi)圖生成
類(lèi)對(duì)象在內(nèi)存中的存儲(chǔ)情況
a)對(duì)象的成員變量存在堆內(nèi)存區(qū)/棧內(nèi)存區(qū),代碼存儲(chǔ)在公有的成員函數(shù)代碼區(qū)。所有的對(duì)象共同享有一段函數(shù)代碼
b)如果使用sizeof 求類(lèi)所占空間的大小,只是計(jì)算了成員變量的大小,并沒(méi)有把成員函數(shù)也包含在內(nèi)。
a)派生類(lèi)的內(nèi)存模型看成是基類(lèi)成員變量和新增成員變量的總和,所有的成員函數(shù)仍然共有另一個(gè)區(qū)域–代碼區(qū)。
創(chuàng)建的時(shí)候先初始化基類(lèi)再初始化派生類(lèi)
釋放時(shí)先釋放派生類(lèi)再釋放基類(lèi)
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("測(cè)試英雄2",999,5000,5000);cout << *hero2 << endl;hero2->Move();//(*hero2).Move(); // 等價(jià)調(diào)用 } void WarriorTest(){Warrior warrior1;// 情況1:派生類(lèi)中沒(méi)有重新實(shí)現(xiàn)move方法,調(diào)用父類(lèi)方法// 情況2:派生類(lèi)中重新實(shí)現(xiàn)move方法,調(diào)用子類(lèi)實(shí)現(xiàn)的該方法warrior1.Move();cout << warrior1 << endl;Hero * hero = new Warrior; // 基類(lèi)指針指向了派生類(lèi)--標(biāo)準(zhǔn)的多態(tài)hero->Move(); // 調(diào)用基類(lèi)的實(shí)現(xiàn)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("默認(rèn)英雄"),m_Level(1),m_MaxLife(100),m_CurrLife(100) {cout << "調(diào)用了Hero的默認(rèn)構(gòu)造" << 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 << "調(diào)用了Hero 一個(gè)參數(shù)版本的構(gòu)造" << endl; } Hero::Hero(const string& nickName, int level):Hero(nickName, level,100,10) {cout << "調(diào)用了Hero 兩個(gè)參數(shù)版本的構(gòu)造" << 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 << "調(diào)用了Hero 四個(gè)參數(shù)版本的構(gòu)造" << endl; } void Hero::Move() {// 默認(rèn)移動(dòng)cout << "普通英雄" << m_NickName << "正在奔跑在艾澤拉斯大陸上" << endl; } ostream& operator<<(ostream& out, const Hero& hero){out << "昵稱(chēng):" << hero.GetNickName() << "\n";out << "等級(jí):" << hero.GetLevel() << "\n";out << "最大生命:" << hero.GetMaxLife() << "\n";out << "當(dāng)前生命:" << 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" // 共有繼承-體現(xiàn)了is a 關(guān)系 class Warrior : public Hero{ private:int m_PhysicalAttack; public:Warrior();Warrior(const string& nickName, int phyAttack);void Move(); // 在派生類(lèi)中實(shí)現(xiàn)派生類(lèi)版本的move方法~Warrior(); }; #endif //CHAPTER13_1_WARRIOR_H //Warrior.cpp // // Created by 陳瑩瑩 on 2021/3/16. // #include "Warrior.h" Warrior::Warrior() :Hero("默認(rèn)構(gòu)造",1,100,100) { } Warrior::Warrior(const string& nickName, int phyAttack):Hero(nickName,1,100,100),m_PhysicalAttack(phyAttack) { } void Warrior::Move() {// m_NickName沒(méi)辦法過(guò)呀,不能訪父類(lèi)的私有屬性,需要在將父類(lèi)中私有成員改為受保護(hù)成員//cout << "戰(zhàn)士《" << m_NickName << "》"<< "背著一大堆近戰(zhàn)武器正在前進(jìn)。。。"<< endl;cout << "戰(zhàn)士《" << GetNickName() << "》"<< "背著一大堆近戰(zhàn)武器正在前進(jìn)。。。"<< endl; } Warrior::~Warrior() { }有關(guān)基類(lèi),派生類(lèi)構(gòu)造
派生類(lèi)與基類(lèi)之間特殊關(guān)系小結(jié)
1.派生類(lèi)可以使用基類(lèi)的非私有成員函數(shù)(public和protect)
2.基類(lèi)指針可以在不進(jìn)行顯示類(lèi)型轉(zhuǎn)換的情況下指向派生類(lèi)對(duì)象
Warrior warrior1("諸葛達(dá)摩", 10, 100, 100); Hero& refHero = warrior1; // 基類(lèi)引用指向派生類(lèi), Hero* ptrHero = &warrior1; // 基類(lèi)指針指向派生類(lèi)對(duì)象 Warrior& warrior2 = (Warrior)refHero; // 父類(lèi)引用/指針需要強(qiáng)制轉(zhuǎn)換成子類(lèi)引用/指針(前提:父類(lèi)指針指向子類(lèi)對(duì)象) //不可以將基類(lèi)對(duì)象的地址賦給派生類(lèi)引用和對(duì)象,即不能進(jìn)行逆操作3.可以將派生類(lèi)對(duì)象賦值給基類(lèi)對(duì)象,程序會(huì)使用隱式重載賦值運(yùn)算符
Hero hero = warrior; hero.move(); //調(diào)用父類(lèi)方法3.私有繼承的例子
沒(méi)講完呀,暫且收一收好了
//main.cpp #include <iostream> #include "Teacher.h" void TeacherTest(){Teacher teacher1(8000);// 名字設(shè)置沒(méi)有寫(xiě)完 } 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; /** 用來(lái)演示私有繼承的其中一種用法* 實(shí)現(xiàn)組合關(guān)系,只能組合一個(gè)屬性不能組合兩個(gè)屬性* Teacher類(lèi)中擁有string類(lèi)型的成員name* */class Teacher :private string{ // teacher 中擁有string類(lèi)型的成員 private:double salary; // 工資public:Teacher();Teacher(int _salary) : salary(_salary){}double GetSalary(){return salary;}void SetSalary(double salary){this->salary = salary;}// 難點(diǎn)const string& GetName() const{/** Teacher類(lèi)是由string 類(lèi)私有派生而來(lái),所以,可以使用強(qiáng)制類(lèi)型轉(zhuǎn)換,將Teacher類(lèi)轉(zhuǎn)換成string類(lèi)* 為了避免調(diào)用構(gòu)造函數(shù)創(chuàng)建新的對(duì)象,所以強(qiáng)制轉(zhuǎn)換成了string 的引用類(lèi)型返回* 本方法返回一引用,指向調(diào)用本方法的Teacher 對(duì)象中繼承而來(lái)的string對(duì)象* */return (const string&)*this; //強(qiáng)轉(zhuǎn)}//using string::length(); //將字符串方法聲明為本類(lèi)的公有方法/*返回當(dāng)前教師類(lèi)對(duì)象姓名的字符串長(zhǎng)度*/int GetLenght(){return string::length();}~Teacher();string nickName; // 使用組合關(guān)系實(shí)現(xiàn)比較簡(jiǎn)單的has-a 關(guān)系protected:}; #endif //CHAPTER13_1_TEACHER_H4. 繼承和組合
一張臉由多個(gè)類(lèi)組合而成,頭發(fā)的不同總類(lèi)從父類(lèi)頭發(fā)那里繼承而來(lái)。
繼承是is a 縱向關(guān)系–狗是哺乳動(dòng)物,戰(zhàn)士是英雄,橘貓是寵物–
組合是has a 橫向關(guān)系–學(xué)生有書(shū)包,戰(zhàn)士有武器,
繼承是C++與C最重要的區(qū)別,雖然C++也可以用C語(yǔ)言的編程習(xí)慣。
總結(jié)
以上是生活随笔為你收集整理的C++(22)--继承和派生的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 网关服务器 .
- 下一篇: UNIX(多线程):22---几种常见的