欧美free性护士vide0shd,老熟女,一区二区三区,久久久久夜夜夜精品国产,久久久久久综合网天天,欧美成人护士h版

首頁綜合 正文
目錄

柚子快報(bào)邀請(qǐng)碼778899分享:java 【C++】多態(tài)詳解

柚子快報(bào)邀請(qǐng)碼778899分享:java 【C++】多態(tài)詳解

http://yzkb.51969.com/

?博客主頁:https://blog.csdn.net/2301_779549673 ?歡迎點(diǎn)贊 ? 收藏 ?留言 ? 如有錯(cuò)誤敬請(qǐng)指正! ?本文由 JohnKi 原創(chuàng),首發(fā)于 CSDN? ?未來很長,值得我們?nè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è)必須重要條件!2.1.2 虛函數(shù)2.1.3虛函數(shù)的重寫/覆蓋2.1.4 多態(tài)場景的一個(gè)選擇題2.1.6 override 和 final關(guān)鍵字

????3.純虛函數(shù)和抽象類????4.多態(tài)的原理????4.2 多態(tài)的原理?總結(jié)

????1. 多態(tài)的概念

多態(tài)(polymorphism)的概念:通俗來說,就是多種形態(tài)。多態(tài)分為編譯時(shí)多態(tài)(靜態(tài)多態(tài))和運(yùn)行時(shí)多態(tài)(動(dòng)態(tài)多態(tài)),這里我們重點(diǎn)講運(yùn)行時(shí)多態(tài),編譯時(shí)多態(tài)(靜態(tài)多態(tài))和運(yùn)行時(shí)多態(tài)(動(dòng)態(tài)多態(tài))。編譯時(shí)多態(tài)(靜態(tài)多態(tài))主要就是我們前面講的函數(shù)重載和函數(shù)模板,他們傳不同類型的參數(shù)就可以調(diào)用不同的函數(shù),通過參數(shù)不同達(dá)到多種形態(tài),之所以叫編譯時(shí)多態(tài),是因?yàn)樗麄儗?shí)參傳給形參的參數(shù)匹配是在編譯時(shí)完成的,我們把編譯時(shí)一般歸為靜態(tài),運(yùn)行時(shí)歸為動(dòng)態(tài)。

運(yùn)行時(shí)多態(tài),具體點(diǎn)就是去完成某個(gè)行為(函數(shù)),可以傳不同的對(duì)象就會(huì)完成不同的行為,就達(dá)到多種形態(tài)。比如買票這個(gè)行為,當(dāng)普通人買票時(shí),是全價(jià)買票;學(xué)生買票時(shí),是優(yōu)惠買票(5折或75折);軍人買票時(shí)是優(yōu)先買票。再比如,同樣是動(dòng)物叫的一個(gè)行為(函數(shù)),傳貓對(duì)象過去,就是喵,傳狗對(duì)象過去,就是狗

????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è)必須重要條件!

必須指針或者引用調(diào)用虛函數(shù)被調(diào)用的函數(shù)必須是虛函數(shù)。

**說明:**要實(shí)現(xiàn)多態(tài)效果,第一必須是基類的指針或引用,因?yàn)橹挥谢惖闹羔樆蛞貌拍芗戎赶蚺缮悓?duì)象:第二派牛類必須對(duì)基類的慮函數(shù)重寫/覆蓋,重寫或者覆蓋了,派生類才能有不同的函數(shù),多態(tài)的不同形態(tài)效果才能達(dá)到。

2.1.2 虛函數(shù)

類成員函數(shù)前面加virtual修飾,那么這個(gè)成員函數(shù)被稱為虛函數(shù)。注意非成員函數(shù)不能加virtual修飾。

class Person

{

public:

virtual void BuyTicket() { cout << "買票-全價(jià)" << endl;}

}

2.1.3虛函數(shù)的重寫/覆蓋

虛函數(shù)的重寫/覆蓋:派生類中有一個(gè)跟基類完全相同的虛函數(shù)(即派生類虛函數(shù)與基類虛函數(shù)的返回值類型、函數(shù)名字、參數(shù)列表完全相同),稱派生類的虛函數(shù)重寫了基類的虛函數(shù)。

**注意:**在重寫基類虛函數(shù)時(shí),派生類的虛函數(shù)在不加virtual關(guān)鍵字時(shí),雖然也可以構(gòu)成重寫(因?yàn)槔^承后基類的虛函數(shù)被繼承下來了在派生類依舊保持虛函數(shù)屬性),但是該種寫法不是很規(guī)范,不建議這樣使用,不過在考試選擇題中,經(jīng)常會(huì)故意買這個(gè)坑,讓你判斷是否構(gòu)成多態(tài)。

class Person {

public:

virtual void BuyTicket() {

cout << "買票-全價(jià)" << endl;

}

};

class Student : public Person {

public:

virtual void BuyTicket() {

cout << "買票-打折" << endl;

}

};

void Func(Person* ptr) {

// 這?可以看到雖然都是Person指針Ptr在調(diào)?BuyTicket

// 但是跟ptr沒關(guān)系,?是由ptr指向的對(duì)象決定的。

ptr->BuyTicket();

}

int main() {

Person ps;

Student st;

Func(&ps);

Func(&st);

return 0;

}

2.1.4 多態(tài)場景的一個(gè)選擇題

class A {

public:

virtual void func(int val = 1) {

std::cout << "A->" << val << std::endl;

}

virtual void test() {

func();

}

};

class B : public A {

public:

void func(int val = 0) {

std::cout << "B->" << val << std::endl;

}

};

int main(int argc, char* argv[]) {

B* p = new B;

p->test();

return 0;

}

首先分析代碼中的類繼承關(guān)系和虛函數(shù)重寫情況:

在這段代碼中,類B繼承自類A。類A中有虛函數(shù)func和test,其中test函數(shù)內(nèi)部調(diào)用了func函數(shù)。類B重寫了func函數(shù)。 然后看函數(shù)調(diào)用情況:

在main函數(shù)中,創(chuàng)建了一個(gè)B類的對(duì)象指針p,并調(diào)用p->test()。由于test函數(shù)在A類中定義,并且func函數(shù)是虛函數(shù),雖然在B類中重寫了func函數(shù),但是虛函數(shù)的默認(rèn)參數(shù)是在編譯時(shí)確定的。當(dāng)B類中的test函數(shù)調(diào)用func時(shí),它會(huì)使用A類中定義的默認(rèn)參數(shù)1(因?yàn)槟J(rèn)參數(shù)不是多態(tài)的一部分,編譯時(shí)綁定)。 最后得出結(jié)果:

程序的輸出結(jié)果是B->1。

2.1.6 override 和 final關(guān)鍵字

從上面可以看出,C++對(duì)函數(shù)重寫的要求比較嚴(yán)格,但是有些情況下由干疏忽,比如函數(shù)名寫錯(cuò)參數(shù)寫錯(cuò)等導(dǎo)致無法構(gòu)成重載,而這種錯(cuò)誤在編譯期間是不會(huì)報(bào)出的,只有在程序運(yùn)行時(shí)沒有得到預(yù)期結(jié)果才來debug會(huì)得不償失,因此C++11提供了override,可以幫助用戶檢測是否重寫。如果我們不想讓派生類重寫這個(gè)虛函數(shù),那么可以用final去修飾。

// error C3668: “Benz::Drive”: 包含重寫說明符“override”的?法沒有重寫任何基類?法

class Car {

public:

virtual void Dirve()

{}

};

class Benz : public Car {

public:

virtual void Drive() override {

cout << "Benz-舒適" << endl;

}

};

int main() {

return 0;

}

// error C3248: “Car::Drive”: 聲明為“final”的函數(shù)?法被“Benz::Drive”重寫

class Car {

public:

virtual void Drive() final {}

};

class Benz : public Car {

public:

virtual void Drive() {

cout << "Benz-舒適" << endl;

}

};

int main() {

return 0;

}

????3.純虛函數(shù)和抽象類

在虛函數(shù)的后面寫上 =0,則這個(gè)函數(shù)為純虛函數(shù),純虛函數(shù)不需要定義實(shí)現(xiàn)(實(shí)現(xiàn)沒啥意義因?yàn)橐慌缮愔貙懀钦Z法上可以實(shí)現(xiàn)),只要聲明即可。包含純虛函數(shù)的類叫做抽象類,抽象類不能實(shí)例化出對(duì)象,如果派生類繼承后不重寫純虛函數(shù),那么派生類也是抽象類。純虛函數(shù)某種程度上強(qiáng)制了派生類重寫虛函數(shù),因?yàn)椴恢貙憣?shí)例化不出對(duì)象。

class Car {

public:

virtual void Drive() = 0;

};

class Benz : public Car {

public:

virtual void Drive() {

cout << "Benz-舒適" << endl;

}

}

class BMW : public Car {

public:

virtual void Drive() {

cout << "BMW-操控" << endl;

}

};

int main() {

// 編譯報(bào)錯(cuò):error C2259: “Car”: ?法實(shí)例化抽象類

Car car;

Car* pBenz = new Benz;

pBenz->Drive();

Car* pBMW = new BMW;

pBMW->Drive();

return 0;

}

????4.多態(tài)的原理

下面編譯為32位程序的運(yùn)行結(jié)果是什么() A.編譯報(bào)錯(cuò) B.運(yùn)行報(bào)錯(cuò) C.8 D. 12

class Base {

public:

virtual void Func1() {

cout << "Func1()" << endl;

}

protected:

int _b = 1;

char _ch = 'x';

};

int main() {

Base b;

cout << sizeof(b) << endl;

return 0;

}

首先分析Base類的結(jié)構(gòu):

Base類中有一個(gè)虛函數(shù)Func1。在C++中,當(dāng)一個(gè)類包含虛函數(shù)時(shí),類對(duì)象中會(huì)包含一個(gè)虛函數(shù)指針(通常是一個(gè)指針的大小,在32位系統(tǒng)中為4字節(jié),在64位系統(tǒng)中為8字節(jié))。類Base還有一個(gè)int類型的成員變量_b(通常為4字節(jié))和一個(gè)char類型的成員變量_ch(1字節(jié))。由于內(nèi)存對(duì)齊的要求,為了提高內(nèi)存訪問效率,編譯器會(huì)在成員變量的布局上進(jìn)行調(diào)整。對(duì)于一個(gè)包含虛函數(shù)指針和int、char類型成員變量的類,在大多數(shù)編譯器下,內(nèi)存布局會(huì)先放置虛函數(shù)指針,然后按照內(nèi)存對(duì)齊規(guī)則放置int和char類型的變量。 然后計(jì)算sizeof(b):

在32位系統(tǒng)中:

虛函數(shù)指針占4字節(jié),int類型的_b占4字節(jié)(按照4字節(jié)對(duì)齊),char類型的_ch占1字節(jié)(總共占4字節(jié),因?yàn)橐獫M足4字節(jié)對(duì)齊)。所以sizeof(b)為12字節(jié)。 在64位系統(tǒng)中:

虛函數(shù)指針占8字節(jié),int類型的_b占4字節(jié)(按照8字節(jié)對(duì)齊,這里會(huì)填充4字節(jié)),char類型的_ch占1字節(jié)(總共占8字節(jié),因?yàn)橐獫M足8字節(jié)對(duì)齊)。所以sizeof(b)為16字節(jié)。

所以運(yùn)行結(jié)果取決于運(yùn)行程序的系統(tǒng)是32位還是64位。如果是32位系統(tǒng),結(jié)果為12;如果是64位系統(tǒng),結(jié)果為16。

????4.2 多態(tài)的原理

從底層的角度Func函數(shù)中ptr->BuyTicket(),是如何作為ptr指向Person對(duì)象調(diào)用Person::BuyTicket,ptr指向Student對(duì)象調(diào)用Student::BuyTicket的呢?通過下圖我們可以看到,滿足多態(tài)條件后,底層不再是編譯時(shí)通過調(diào)用對(duì)象確定函數(shù)的地址,而是運(yùn)行時(shí)到指向的對(duì)象的虛表中確定對(duì)應(yīng)的虛函數(shù)的地址,這樣就實(shí)現(xiàn)了指針或引用指向基類就調(diào)用基類的虛函數(shù),指向派生類就調(diào)用派生類對(duì)應(yīng)的虛函數(shù)。第一張圖,ptr指向的Person對(duì)象,調(diào)用的是Person的虛函數(shù);第二張圖,ptr指向的Student對(duì)象,調(diào)用的是Student的虛函數(shù)。

class Person {

public:

virtual void BuyTicket() {

cout << "買票-全價(jià)" << endl;

}

};

class Student : public Person {

public:

virtual void BuyTicket() {

cout << "買票-打折" << endl;

}

};

class Soldier: public Person {

public:

virtual void BuyTicket() {

cout << "買票-優(yōu)先" << endl;

}

};

void Func(Person* ptr) {

// 這?可以看到雖然都是Person指針Ptr在調(diào)?BuyTicket

// 但是跟ptr沒關(guān)系,?是由ptr指向的對(duì)象決定的。

ptr->BuyTicket();

}

int main() {

// 其次多態(tài)不僅僅發(fā)?在派?類對(duì)象之間,多個(gè)派?類繼承基類,重寫虛函數(shù)后

// 多態(tài)也會(huì)發(fā)?在多個(gè)派?類之間。

Person ps;

Student st;

Soldier sr;

Func(&ps);

Func(&st);

Func(&sr);

return 0;

}

?總結(jié)

本篇博文對(duì) 【C++】多態(tài)詳解 做了一個(gè)較為詳細(xì)的介紹,不知道對(duì)你有沒有幫助呢

覺得博主寫得還不錯(cuò)的三連支持下吧!會(huì)繼續(xù)努力的~

柚子快報(bào)邀請(qǐng)碼778899分享:java 【C++】多態(tài)詳解

http://yzkb.51969.com/

推薦文章

評(píng)論可見,查看隱藏內(nèi)容

本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場。

轉(zhuǎn)載請(qǐng)注明,如有侵權(quán),聯(lián)系刪除。

本文鏈接:http://gantiao.com.cn/post/19568242.html

發(fā)布評(píng)論

您暫未設(shè)置收款碼

請(qǐng)?jiān)谥黝}配置——文章設(shè)置里上傳

掃描二維碼手機(jī)訪問

文章目錄