網(wǎng)站開發(fā)規(guī)劃seo運營做什么
博主介紹:程序喵大人
- 35- 資深C/C++/Rust/Android/iOS客戶端開發(fā)
- 10年大廠工作經(jīng)驗
- 嵌入式/人工智能/自動駕駛/音視頻/游戲開發(fā)入門級選手
- 《C++20高級編程》《C++23高級編程》等多本書籍著譯者
- 更多原創(chuàng)精品文章,首發(fā)gzh,見文末
- 👇👇記得訂閱專欄,以防走丟👇👇
😃C++基礎(chǔ)系列專欄
😃C語言基礎(chǔ)系列
本文主要介紹下多態(tài)的概念。
繼承與抽象類
多態(tài)是面向?qū)ο蟮暮诵闹R點,在C++中意味著調(diào)用對象成員函數(shù)時,會根據(jù)對象的真實類型來執(zhí)行不同的函數(shù),從而產(chǎn)生不同的行為。
- 比如同樣是人,不同人的聲音不相同。
- 比如同樣是公司,不同公司的經(jīng)營業(yè)務(wù)也不同。
這就可以就多態(tài)來解釋。
那怎么實現(xiàn)多態(tài),看這段代碼,先定義一個People
類:
class People {
public:
virtual void Speak() { std::cout << "People Speak \n"; }
};
注意這里面的函數(shù)使用了virtual
修飾,用virtual
修飾的函數(shù)表示虛函數(shù),帶虛函數(shù)的類可以稱之為父類,有父類自然可以派生出子類,子類可以覆蓋父類的行為。
這里再定義兩個類,一個男人類
,一個女人類
class MalePeople : public People {
public:
void Speak() { std::cout << "MalePeople Speak \n"; }
};class FemalePeople : public People {
public:
void Speak() { std::cout << "FemalePeople Speak \n"; }
};
在MalePeople
和FemalePeople
使用了冒號,表示繼承,冒號后面的public
表示繼承的權(quán)限。
所以上面的代碼的含義是:
MalePeople
以public
權(quán)限繼承了People
,并覆蓋父類People
的Speak
行為。
FemalePeople
以public
權(quán)限繼承了People
,并覆蓋父類People
的Speak
行為。
再看一段使用多態(tài)的代碼:
int main() {People *p1 = new People();People *p2 = static_cast<People *>(new MalePeople());People *p3 = static_cast<People *>(new FemalePeople());p1->Speak(); // People Speakp2->Speak(); // MalePeople Speakp3->Speak(); // FemalePeople Speakdelete p3;delete p2;delete p1;
}
p1、p2、p3
都是People
的實例,但是通過他們的實例調(diào)用相同的函數(shù)卻產(chǎn)生了不同的行為,這就是多態(tài)。
注意兩點,想要實現(xiàn)上述的多態(tài)行為:
- 父類相應(yīng)的函數(shù)一定要使用
virtual
修飾 - 一定要父類的指針或引用指向子類對象
繼承權(quán)限
共有三種繼承權(quán)限:
public
繼承
- 父類中所有
public
成員在子類中為public
屬性 - 父類中所有
protected
成員在子類中為protected
屬性 - 父類中所有
private
成員在子類中不可訪問
protected
繼承
- 父類中所有
public
成員在子類中為protected
屬性 - 父類中所有
protected
成員在子類中為protected
屬性 - 父類中所有
private
成員在子類中不可訪問
private
繼承
- 父類中所有
public
成員在子類中為private
屬性 - 父類中所有
protected
成員在子類中為private
屬性 - 父類中所有
private
成員在子類中不可訪問
大體可以理解為:
- 父類成員在子類中的訪問權(quán)限不會高于指定的繼承權(quán)限。
- 父類中的
private
成員在子類中使用不可訪問。
然而平時開發(fā)過程中一般都會使用public
繼承,其他的繼承方式很少。
純虛函數(shù)
在C++中,還有個純虛函數(shù)的概念,就是在virtual
修飾的基礎(chǔ)上加個=0
,比如:
class People {
public:
virtual void Speak() = 0;
};
這里的Speak
就是純虛函數(shù),含有純虛函數(shù)的類叫抽象類,同時規(guī)定抽象類不允許被實例化,只能通過子類實例化,舉例:
int main() {People *p1 = new People(); // compile errorPeople *p2 = static_cast<People *>(new MalePeople());People *p3 = static_cast<People *>(new FemalePeople());
}
多繼承
就是子類繼承了多個父類,比如一個男子籃球運動員,那就可以定義兩個父類,一個MalePeople
類,一個BasketballPlayer
類,那如果想要定義男子籃球運動員
類,可以定義一個MaleBasketballPlayer
類,繼承MalePeople
和BaskeballPlayer
,代碼如下:
class MalePeople {
public:
void Speak() { std::cout << "MalePeople Speak \n"; }
};class BasketBallPlayer {
public:
void Play() { std::cout << "Play Basketball \n"; }
};class MaleBasketBallPlayer : public MalePeople, public BasketBallPlayer {};
和單繼承方式差不多,只是用相同的語法在后面再派生多個即可。
虛繼承
普通的繼承就是非虛繼承,如圖, 非虛繼承時,顯然D會繼承兩次A,內(nèi)部就會存儲兩份A的數(shù)據(jù)浪費空間,而且還有二義性,D調(diào)用A的方法時,由于有兩個A,究竟時調(diào)用哪個A的方法呢,編譯器也不知道,就會報錯,所以有了虛繼承,解決了空間浪費以及二義性問題。
在虛擬繼承下,只有一個共享的基類子對象被繼承,而無論該基類在派生層次中出現(xiàn)多少次。共享的基類子對象被稱為虛基類。在虛繼承下,基類子對象的復(fù)制及由此而引起的二義性都被消除了。
如何使用虛繼承?
在繼承的時候使用virtual
關(guān)鍵字,代碼如下:
struct Base {
virtual void Func() { printf("Base Func\n"); }
};struct BaseA : virtual public Base {
virtual void Func() { printf("BaseA Func\n"); }
};struct BaseB : virtual public Base {
virtual void Func() { printf("BaseB Func\n"); }
};struct Derive : public BaseB, public BaseA {
void Func() override { printf("Derive Func \n"); }
};
注意,為了易于觀察,上面所有的父類都沒有定義析構(gòu)函數(shù),正常父類的析構(gòu)函數(shù)一定要設(shè)置成virtual
。
練習(xí)
- 多態(tài)只有這一種方式嗎?
- 為什么一定要通過指針或引用方式才能達(dá)到多態(tài)的目的?
- 為什么析構(gòu)函數(shù)一定要設(shè)置成virtual?
- 構(gòu)造函數(shù)可以為虛函數(shù)嗎?
- 多態(tài)的原理是怎么樣的?
- 不同繼承方式下,類對象的布局是什么結(jié)構(gòu)?
碼字不易,歡迎大家點贊,關(guān)注,評論,謝謝!
C++訓(xùn)練營
專為校招、社招3年工作經(jīng)驗的同學(xué)打造的1V1 C++訓(xùn)練營,量身定制學(xué)習(xí)計劃、每日代碼review,簡歷優(yōu)化,面試輔導(dǎo),已幫助多名學(xué)員獲得offer!訓(xùn)練營介紹