(上))
多態(tài)上文章目錄多態(tài)上1. 多態(tài)的概念2. 多態(tài)的定義及實(shí)現(xiàn)2.1 多態(tài)的構(gòu)成條件2.1.1 實(shí)現(xiàn)多態(tài)還有兩個(gè)必須重要條件結(jié)合動(dòng)物例子串起來(lái)看2.1.2 虛函數(shù)2.1.3 虛函數(shù)的重寫/覆蓋坑點(diǎn)總結(jié)2.1.4 多態(tài)場(chǎng)景的?個(gè)選擇題2.1.5 虛函數(shù)重寫的?些其他問題1.協(xié)變Covariance1.1 結(jié)合協(xié)變代碼講解:1.2 協(xié)變完整帶注釋代碼2. 析構(gòu)函數(shù)的虛函數(shù)重寫面試重點(diǎn)最重要實(shí)際意義面試核心1. 析構(gòu)代碼逐行講解反面場(chǎng)景坑2. 虛析構(gòu)完整帶注釋代碼3. 考試 / 面試小結(jié)2.1.6 override 和final關(guān)鍵字1、override檢查是否成功重寫虛函數(shù)問題背景override 的作用2. final兩個(gè)用途用途 1修飾虛函數(shù) —— 禁止派生類重寫這個(gè)虛函數(shù)用途 2修飾類 —— 禁止這個(gè)類被繼承總結(jié)補(bǔ)充小對(duì)比2.1.7 重載/重寫/隱藏的對(duì)比1. 重載同一作用域2. 重寫 / 覆蓋實(shí)現(xiàn)多態(tài)繼承體系 virtual 虛函數(shù)3. 隱藏又叫遮蔽繼承體系不滿足重寫條件總結(jié)對(duì)照表方便記憶1. 多態(tài)的概念同一個(gè)動(dòng)作交給不同對(duì)象去做表現(xiàn)出不一樣的效果這就是多態(tài)多種形態(tài)多態(tài)分成兩大類靜態(tài)多態(tài)編譯時(shí)、動(dòng)態(tài)多態(tài)運(yùn)行時(shí)靜態(tài)多態(tài)【編譯階段就確定好調(diào)用哪個(gè)函數(shù)】代表函數(shù)重載、模板同一個(gè)函數(shù)名字根據(jù)你傳入不同參數(shù)直接確定執(zhí)行哪段代碼程序還沒跑起來(lái)編譯的時(shí)候編譯器一看參數(shù)就知道要用哪個(gè)方法。舉例子add(1,2)兩個(gè)數(shù)字相加add(a,b)兩個(gè)字符串拼接函數(shù)名都是 add參數(shù)不一樣功能不一樣。代碼編譯的時(shí)候就分清調(diào)用哪個(gè)所以叫靜態(tài) / 編譯時(shí)多態(tài)。動(dòng)態(tài)多態(tài)【程序跑起來(lái)之后才確定執(zhí)行什么代碼】面向?qū)ο笾攸c(diǎn)規(guī)則同一個(gè)行為傳入不同對(duì)象產(chǎn)生不同結(jié)果程序運(yùn)行的時(shí)候才決定用哪段邏輯原文兩個(gè)例子通俗翻譯例子 1買票動(dòng)作【買票】普通人對(duì)象執(zhí)行買票 → 付全款學(xué)生對(duì)象執(zhí)行買票 → 半價(jià)優(yōu)惠軍人對(duì)象執(zhí)行買票 → 優(yōu)先購(gòu)票動(dòng)作名稱不變都是 “買票”對(duì)象不一樣行為結(jié)果不一樣。例子 2動(dòng)物叫喚統(tǒng)一動(dòng)作【叫】貓對(duì)象調(diào)用【叫】 → 喵喵喵狗對(duì)象調(diào)用【叫】 → 汪汪汪靜態(tài)多態(tài) vs 動(dòng)態(tài)多態(tài)最簡(jiǎn)單區(qū)分? 靜態(tài)多態(tài)看參數(shù)區(qū)分邏輯編譯時(shí)定好? 動(dòng)態(tài)多態(tài)看對(duì)象區(qū)分邏輯程序運(yùn)行時(shí)才確定2. 多態(tài)的定義及實(shí)現(xiàn)2.1 多態(tài)的構(gòu)成條件多態(tài)是?個(gè)繼承關(guān)系的下的類對(duì)象去調(diào)?同?函數(shù)產(chǎn)?了不同的?為。?如Student繼承了 Person。Person對(duì)象買票全價(jià)Student對(duì)象優(yōu)惠買票。2.1.1 實(shí)現(xiàn)多態(tài)還有兩個(gè)必須重要條件條件 1要用基類指針 / 基類引用去調(diào)用函數(shù)基類相當(dāng)于通用模板比如人、動(dòng)物派生類是具體種類學(xué)生、貓、軍人、狗。普通指針只能固定指向一種對(duì)象基類指針 / 引用很靈活既能指向父類對(duì)象也能指向子類對(duì)象。舉例子基類 動(dòng)物派生類 貓、狗動(dòng)物* p; // 基類指針 p new 貓(); // 可以指向貓 p new 狗(); // 也可以指向狗如果不用基類指針直接用貓指針只能指向貓狗指針只能指向狗沒法統(tǒng)一用一套代碼接收多種子類自然談不上多態(tài)。簡(jiǎn)單理解基類指針就是一個(gè) “通用容器”能裝下所有子類。條件 2調(diào)用的函數(shù)必須是虛函數(shù)并且子類完成重寫覆蓋基類里的函數(shù)前面加上virtual它就變成虛函數(shù)。派生類寫一個(gè)一模一樣的函數(shù)函數(shù)名、參數(shù)、返回值完全匹配這就叫重寫 / 覆蓋。沒有虛函數(shù)會(huì)發(fā)生什么就算基類指針指向貓、指向狗調(diào)用方法時(shí)只會(huì)死板執(zhí)行基類里面的代碼不會(huì)自動(dòng)調(diào)用貓、狗自己實(shí)現(xiàn)的版本出不來(lái)多態(tài)效果虛函數(shù)作用相當(dāng)于給程序開了一個(gè)開關(guān)。程序運(yùn)行的時(shí)候不去死板看指針是什么類型而是看指針真正指向的是什么對(duì)象調(diào)用這個(gè)對(duì)象自己重寫的函數(shù)。結(jié)合動(dòng)物例子串起來(lái)看基類【動(dòng)物】里面寫虛函數(shù)virtual 叫()子類【貓】重寫叫()喵喵喵子類【狗】重寫叫()汪汪汪動(dòng)物* a new 貓(); a-叫(); // 輸出喵喵喵 a new 狗(); a-叫(); // 輸出汪汪汪滿足兩條規(guī)則多態(tài)生效以下是反面教材如果函數(shù)不加 virtual不是虛函數(shù)基類指針哪怕指向貓調(diào)用叫()只會(huì)執(zhí)行動(dòng)物默認(rèn)的叫聲不會(huì)調(diào)用貓的版本。如果不用基類指針直接用貓指針、狗指針各自調(diào)用雖然也能正常叫喚但是只是普通函數(shù)調(diào)用不是多態(tài)沒法用統(tǒng)一的指針接收所有子類。2.1.2 虛函數(shù)類成員函數(shù)前?加virtual修飾那么這個(gè)成員函數(shù)被稱為虛函數(shù)。注意?成員函數(shù)不能加virtual修飾。class Person { public: virtual void BuyTicket() { cout 買票全價(jià) endl;} };2.1.3 虛函數(shù)的重寫/覆蓋(1)定義基類寫了一個(gè)虛函數(shù)子類里面寫一個(gè)函數(shù)函數(shù)名一模一樣、參數(shù)一模一樣、返回值符合要求。這就叫子類重寫覆蓋了基類虛函數(shù)。(2) 重點(diǎn)注意點(diǎn)子類可以不寫virtual依然能構(gòu)成重寫基類函數(shù)已經(jīng)是虛函數(shù)繼承到子類后這個(gè)函數(shù)天生自帶虛函數(shù)身份。哪怕子類函數(shù)前面省略virtual依舊算是重寫多態(tài)照樣生效。?但是不推薦省略 virtual代碼可讀性很差規(guī)范開發(fā)都建議寫上??荚嚫哳l坑選擇題經(jīng)常故意把子類的virtual刪掉迷惑你很多人誤以為沒有 virtual 就不能重寫、無(wú)法多態(tài)這是易錯(cuò)點(diǎn)。簡(jiǎn)單記住虛屬性是從基類繼承下來(lái)的子類可省略 virtual但規(guī)范上一定要加上。(3) 補(bǔ)充一個(gè)硬性前提想要實(shí)現(xiàn)動(dòng)態(tài)多態(tài)必須滿足重寫如果函數(shù)名字 / 參數(shù)不一樣那不叫重寫自然觸發(fā)不了多態(tài)。4結(jié)合兩段代碼講解案例 1買票 Person Studentclass Person { public: virtual void BuyTicket() { cout 買票-全價(jià) endl; } }; class Student : public Person { public: virtual void BuyTicket() { cout 買票-打折 endl; } };基類PersonBuyTicket()帶有virtual是虛函數(shù)子類Student函數(shù)名BuyTicket、參數(shù)列表、返回值和基類完全一致 →構(gòu)成重寫void Func(Person* ptr) // 條件1基類指針 { ptr-BuyTicket(); } int main() { Person ps; Student st; Func(ps); // 普通人類對(duì)象 → 全價(jià)買票 Func(st); // 學(xué)生對(duì)象 → 打折買票 return 0; }? 兩條動(dòng)態(tài)多態(tài)條件全部滿足① 使用基類指針調(diào)用函數(shù)② 虛函數(shù) 子類完成重寫運(yùn)行結(jié)果買票-全價(jià) 買票-打折 關(guān)鍵點(diǎn)指針永遠(yuǎn)都是Person*類型但是程序運(yùn)行時(shí)看指針指向什么對(duì)象就調(diào)用哪個(gè)類的函數(shù)這就是多態(tài)。拓展測(cè)試把 Student 里面的 virtual 刪掉void BuyTicket() { cout 買票-打折 endl; }依然構(gòu)成重寫多態(tài)依舊生效只是代碼不規(guī)范考試要認(rèn)清這個(gè)情況。案例 2動(dòng)物叫聲 Animal Dog Catclass Animal { public: virtual void talk() const {} }; class Dog : public Animal { public: virtual void talk() const { std::cout 汪汪 std::endl; } }; class Cat : public Animal { public: virtual void talk() const { std::cout (^ω^)喵 std::endl; } };基類Animal擁有虛函數(shù)talk()Dog、Cat 中talk()函數(shù)名、參數(shù)、const 修飾、返回值完全匹配基類構(gòu)成重寫。void letsHear(const Animal animal) // 條件1基類引用指針/引用二選一都可以 { animal.talk(); } int main() { Cat cat; Dog dog; letsHear(cat); letsHear(dog); return 0; }? 使用基類引用也是實(shí)現(xiàn)多態(tài)合法方式 虛函數(shù)重寫滿足條件。運(yùn)行結(jié)果(^ω^)喵 汪汪再次區(qū)分指針、引用都能實(shí)現(xiàn)多態(tài)直接用父類對(duì)象接收子類值傳遞切割無(wú)法實(shí)現(xiàn)多態(tài)坑點(diǎn)總結(jié)子類重寫虛函數(shù)時(shí)省略 virtual依舊是重寫能夠觸發(fā)多態(tài)很多考生誤以為子類必須寫 virtual 才算重寫這是出題人最愛設(shè)置的陷阱但是工程開發(fā)規(guī)范建議子類重寫虛函數(shù)時(shí)主動(dòng)寫上 virtualC11 推薦再加 override 關(guān)鍵字如果函數(shù)名 / 參數(shù)不一樣不叫重寫叫函數(shù)隱藏?zé)o法實(shí)現(xiàn)多態(tài)2.1.4 多態(tài)場(chǎng)景的?個(gè)選擇題各位大佬請(qǐng)亮出您的答案答案B: B-1解釋先看能不能觸發(fā)多態(tài)基類 Avirtual void func(int val 1)派生類 Bvoid func(int val 0)函數(shù)名、返回值、參數(shù)列表完全相同構(gòu)成虛函數(shù)重寫子類不寫 virtual 依然有效。調(diào)用流程梳理B* p new B; p-test();test()這個(gè)函數(shù)定義在 A 類里面virtual void test(){ func(); }雖然 test 寫在 A 中但是 test 內(nèi)部調(diào)用func()。由于 func 是虛函數(shù)會(huì)觸發(fā)多態(tài)執(zhí)行 B 類重寫的 func。重點(diǎn)最終跑的是B::func()不是 A::func ()。最容易踩坑默認(rèn)參數(shù)編譯期確定不參與多態(tài)? 記住鐵律虛函數(shù)是運(yùn)行時(shí)確定調(diào)用哪個(gè)函數(shù)函數(shù)默認(rèn)參數(shù)值是編譯階段就確定好的不會(huì)跟著子類改變test()屬于 A 類的成員函數(shù)編譯的時(shí)候編譯器看到func();無(wú)傳參直接拿A 類 func 的默認(rèn)參數(shù) val1。運(yùn)行時(shí)執(zhí)行的是 B 的 func 函數(shù)但傳入的參數(shù)值是編譯期敲定的1。最終執(zhí)行運(yùn)行B::func(1)打印輸出B-1總結(jié)調(diào)用哪個(gè)函數(shù)A::func 還是 B::func運(yùn)行時(shí)看虛函數(shù)參數(shù)默認(rèn)值在編譯時(shí)就定死由調(diào)用處所在的類版本決定不會(huì)動(dòng)態(tài)跟隨子類易錯(cuò)辨析很多人會(huì)誤以為調(diào)用 B 的 func就應(yīng)該使用 B 的默認(rèn)參數(shù) 0。?錯(cuò)誤默認(rèn)參數(shù)不參與動(dòng)態(tài)多態(tài)編譯時(shí)在 A 的 test 函數(shù)內(nèi)部func 不傳參直接綁定 A 的默認(rèn)值 1。拓展驗(yàn)證如果代碼寫成A* p new B(); p-func(); // 依然輸出 B-1同樣原理對(duì)應(yīng)選項(xiàng): 選項(xiàng)B: B-1?簡(jiǎn)易流程圖p-test()→ 執(zhí)行 A::test () → test 里面調(diào)用 func ()→ 虛函數(shù)多態(tài)運(yùn)行找到 B::func→ 參數(shù)編譯階段確定為 A 的默認(rèn)值1→ 執(zhí)行B::func(1)→ 輸出B-12.1.5 虛函數(shù)重寫的?些其他問題1.協(xié)變Covariance正常虛函數(shù)重寫要求返回值必須一模一樣。協(xié)變是唯一的特例基類虛函數(shù)返回【基類指針 / 基類引用】派生類重寫的虛函數(shù)返回【派生類指針 / 派生類引用】這種返回值不一樣但依然合法構(gòu)成重寫就叫做協(xié)變。?? 硬性限制只允許指針、引用普通對(duì)象不能協(xié)變必須是「基類 ← 派生類」的繼承關(guān)系日常開發(fā)極少使用了解概念即可。1.1 結(jié)合協(xié)變代碼講解:class A {}; class B : public A {}; class Person { public: virtual A* BuyTicket() { cout 買票-全價(jià) endl; return nullptr; } }; class Student : public Person { public: virtual B* BuyTicket() { cout 買票-打折 endl; return nullptr; } };基類虛函數(shù)返回A*子類重寫函數(shù)返回B*B 公有繼承 A滿足協(xié)變條件 →合法重寫可以觸發(fā)多態(tài)void Func(Person* ptr) { ptr-BuyTicket(); } int main() { Person ps; Student st; Func(ps); // 輸出買票-全價(jià) Func(st); // 輸出買票-打折 return 0; }運(yùn)行邏輯Func 接收基類指針調(diào)用 BuyTicket。因?yàn)闃?gòu)成合法重寫多態(tài)生效。ptr 指向 Student 對(duì)象自動(dòng)執(zhí)行 Student::BuyTicket。1.2 協(xié)變完整帶注釋代碼#include iostream using namespace std; class A {}; // B公有繼承A滿足協(xié)變的繼承關(guān)系 class B : public A {}; class Person { public: // 基類虛函數(shù)返回基類A的指針 virtual A* BuyTicket() { cout 買票-全價(jià) endl; return nullptr; } }; class Student : public Person { public: // 協(xié)變返回派生類B*允許構(gòu)成重寫 virtual B* BuyTicket() { cout 買票-打折 endl; return nullptr; } }; // 參數(shù)基類指針滿足動(dòng)態(tài)多態(tài)條件 void Func(Person* ptr) { ptr-BuyTicket(); } int main() { Person ps; Student st; Func(ps); Func(st); return 0; }2. 析構(gòu)函數(shù)的虛函數(shù)重寫面試重點(diǎn)正常成員函數(shù)重寫函數(shù)名、參數(shù)必須完全相同。析構(gòu)函數(shù)是編譯器特殊處理的例外源代碼里基類析構(gòu)~A()派生類析構(gòu)~B()名字看起來(lái)不同編譯階段編譯器把所有析構(gòu)函數(shù)統(tǒng)一改名destructor只要基類析構(gòu)加 virtual派生類析構(gòu)自動(dòng)構(gòu)成重寫派生類析構(gòu)寫不寫 virtual 都有效。最重要實(shí)際意義面試核心當(dāng)用基類指針指向派生類對(duì)象執(zhí)行delete 指針;如果基類析構(gòu)不是虛函數(shù)只會(huì)調(diào)用基類析構(gòu)派生類析構(gòu)不執(zhí)行。派生類里面申請(qǐng)的內(nèi)存無(wú)法釋放 →內(nèi)存泄漏。如果基類析構(gòu)是虛函數(shù)觸發(fā)多態(tài)先調(diào)用派生類析構(gòu)再調(diào)用基類析構(gòu)資源完整釋放。1. 析構(gòu)代碼逐行講解class A { public: // 基類析構(gòu)設(shè)置為virtual virtual ~A() { cout ~A() endl; } }; class B : public A { public: // 自動(dòng)重寫基類虛析構(gòu)可省略virtual ~B() { cout ~B()-delete: _p endl; delete[] _p; // 釋放子類申請(qǐng)的堆內(nèi)存 } protected: int* _p new int[10]; // 子類持有堆資源 };int main() { A* p1 new A; A* p2 new B; delete p1; // 釋放A對(duì)象調(diào)用 ~A() delete p2; // 基類析構(gòu)是虛函數(shù)觸發(fā)多態(tài) // 先調(diào)用 ~B() 釋放_(tái)p數(shù)組再調(diào)用 ~A() return 0; }? 運(yùn)行輸出~A() ~B()-delete:0x... ~A()反面場(chǎng)景坑如果刪掉virtual變成~A(){}delete p2;只會(huì)執(zhí)行~A()不會(huì)執(zhí)行B ()_p指向的堆數(shù)組沒有釋放永久內(nèi)存泄漏。面試標(biāo)準(zhǔn)答案如果一個(gè)類可能被繼承最好把基類析構(gòu)定義為虛析構(gòu)函數(shù)防止基類指針管理派生類對(duì)象時(shí)發(fā)生內(nèi)存泄漏。2. 虛析構(gòu)完整帶注釋代碼#include iostream using namespace std; class A { public: // 重點(diǎn)基類析構(gòu)加上virtual成為虛析構(gòu)函數(shù) virtual ~A() { cout ~A() endl; } }; class B : public A { public: // 自動(dòng)重寫基類虛析構(gòu)virtual可寫可不寫推薦寫上增強(qiáng)可讀性 ~B() { cout ~B()-delete: _p endl; delete[] _p; // 釋放子類堆資源 } protected: // 子類在堆上開辟內(nèi)存 int* _p new int[10]; }; int main() { A* p1 new A; A* p2 new B; delete p1; delete p2; return 0; }3. 考試 / 面試小結(jié)協(xié)變僅支持指針 / 引用日常開發(fā)很少用認(rèn)識(shí)即可析構(gòu)函數(shù)名稱源代碼不同編譯器統(tǒng)一改名滿足虛函數(shù)重寫條件被繼承的基類析構(gòu)函數(shù)建議加 virtual避免基類指針 delete 派生類對(duì)象造成內(nèi)存泄漏。2.1.6 override 和final關(guān)鍵字1、override檢查是否成功重寫虛函數(shù)問題背景虛函數(shù)重寫要求很嚴(yán)函數(shù)名、參數(shù)、返回值協(xié)變除外都要匹配。一不小心寫錯(cuò)函數(shù)名、參數(shù)編譯器不會(huì)報(bào)錯(cuò)它只會(huì)認(rèn)為你在派生類新增了一個(gè)獨(dú)立函數(shù)沒有完成重寫。等到運(yùn)行程序多態(tài)失效結(jié)果不對(duì)你還要花大量時(shí)間查 bug。override 的作用在派生類的虛函數(shù)后面寫上override編譯器會(huì)主動(dòng)檢查這個(gè)函數(shù)能不能成功重寫基類的虛函數(shù)。滿足重寫規(guī)則正常編譯寫錯(cuò)名字 / 參數(shù)無(wú)法構(gòu)成重寫直接編譯報(bào)錯(cuò)提前發(fā)現(xiàn)錯(cuò)誤。示例class A { public: virtual void func(){} }; class B : public A { public: // 正確成功重寫 void func() override{} // void func(int x) override{} // 報(bào)錯(cuò)參數(shù)不一樣無(wú)法重寫 };小建議寫重寫的虛函數(shù)時(shí)習(xí)慣性加上 override。2. final兩個(gè)用途用途 1修飾虛函數(shù) —— 禁止派生類重寫這個(gè)虛函數(shù)基類虛函數(shù)后面加final后續(xù)所有子類都不能重寫它。子類強(qiáng)行重寫 → 編譯報(bào)錯(cuò)。class A { public: virtual void func() final {} }; class B : public A { public: // void func(){} // 編譯報(bào)錯(cuò)func被final禁止重寫 };用途 2修飾類 —— 禁止這個(gè)類被繼承類名后面加 final別的類不能繼承它c(diǎn)lass A final {}; // class B:public A{}; // 報(bào)錯(cuò)A不能被繼承總結(jié)override告訴編譯器「我打算重寫虛函數(shù)幫我檢查有沒有寫錯(cuò)」防止隱性 bug。final上鎖。修飾函數(shù) 不讓子類重寫修飾類 不讓別人繼承這個(gè)類。補(bǔ)充小對(duì)比override只用在派生類的虛函數(shù)final可以寫在基類虛函數(shù)后也可以寫在類名后2.1.7 重載/重寫/隱藏的對(duì)比如果追女生是每個(gè)少年男生心中第一件事喵那么搞清楚這三個(gè)對(duì)比就是現(xiàn)在的當(dāng)務(wù)之急重中之重喵。其實(shí)我想說這是第0件事哈哈哈哈哈因?yàn)橛?jì)算機(jī)的世界是二進(jìn)制的花園喵先一句話分清場(chǎng)景重載同一個(gè)班級(jí)里重寫父子班級(jí) 虛函數(shù)隱藏父子班級(jí)、但是達(dá)不到重寫條件。1. 重載同一作用域條件同一個(gè)范圍函數(shù)名字一樣參數(shù)不一樣。例子班里同一個(gè)教室同一個(gè)類 / 同一個(gè)作用域有兩位老師都叫 “講課”講課 (講數(shù)學(xué))講課 (講語(yǔ)文)名字都叫講課但是授課內(nèi)容參數(shù)不同。調(diào)用的時(shí)候看你傳什么參數(shù)自動(dòng)匹配對(duì)應(yīng)函數(shù)。關(guān)鍵點(diǎn)全都在同一個(gè)教室同一作用域和繼承沒關(guān)系。返回值隨便可以相同也可以不同只看參數(shù)。// 同一個(gè)類內(nèi)部屬于重載 class Person { public: void Talk(string subject); void Talk(int age); };2. 重寫 / 覆蓋實(shí)現(xiàn)多態(tài)繼承體系 virtual 虛函數(shù)條件父類、子類兩個(gè)不同作用域父類函數(shù)是 virtual 虛函數(shù)函數(shù)名、參數(shù)一致協(xié)變除外。例子父親開小店virtual 買票 () → 全價(jià)票兒子繼承店鋪重新改造規(guī)則買票 () → 學(xué)生打折票規(guī)則名稱一模一樣入?yún)⒁粯?。有人通過店鋪招牌父類指針買票時(shí)自動(dòng)區(qū)分是誰(shuí)經(jīng)營(yíng)店鋪執(zhí)行對(duì)應(yīng)的買票邏輯這就是多態(tài)。重點(diǎn)區(qū)別必須加virtual不加就不叫重寫。只有重寫才能觸發(fā)動(dòng)態(tài)多態(tài)。class Person { public: virtual void BuyTicket() { cout 全價(jià)票; } }; class Student : public Person { public: void BuyTicket() override { cout 打折票; } // 重寫 };3. 隱藏又叫遮蔽繼承體系不滿足重寫條件規(guī)則父子類函數(shù)名相同只要構(gòu)不成重寫全部是隱藏。兩種常見情況1父類沒有寫 virtual2有 virtual但是參數(shù)列表不一樣例子父親店鋪功能買票 ()無(wú)參數(shù)兒子店鋪買票 (int num)帶參數(shù)名字都叫買票但是參數(shù)不一樣。如果你拿著兒子店鋪的招牌調(diào)用買票 ()只會(huì)看到兒子自己的版本父親同名函數(shù)直接被藏起來(lái)了。想要調(diào)用父類版本必須手動(dòng)指定Person::BuyTicket()。?? 重要坑隱藏≠重寫不會(huì)觸發(fā)多態(tài)額外補(bǔ)充父子類同名成員變量也屬于隱藏父親有個(gè)變量int id;子類也寫int id;子類 id 會(huì)隱藏父類 id。class Person { public: virtual void BuyTicket() { cout 全價(jià)票; } }; class Student : public Person { public: void BuyTicket(int x) { cout 打折票; } // 參數(shù)不一樣無(wú)法構(gòu)成重寫屬于【隱藏】 };總結(jié)對(duì)照表方便記憶重載同一個(gè)房間同名不同參重寫父子房間、帶 virtual、簽名一致實(shí)現(xiàn)多態(tài)隱藏父子房間、名字相同但達(dá)不到重寫標(biāo)準(zhǔn)父類同名成員被遮蔽又是美好的一天各位觀眾姥爺們?nèi)粲惺裁床欢牡胤綒g迎在評(píng)論區(qū)留言哦我會(huì)給出相應(yīng)解釋的。如有什么疏忽的細(xì)節(jié)請(qǐng)點(diǎn)出我會(huì)及時(shí)糾正。感謝觀看。喵喵