欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C/C++使用C語言實(shí)現(xiàn)多態(tài)

 更新時間:2021年08月18日 15:19:16   作者:久病成良醫(yī)  
這篇文章主要介紹了C/C++多態(tài)的實(shí)現(xiàn)機(jī)制理解的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下,希望能給你帶來幫助

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

1.1什么是多態(tài)?

多態(tài)是在不同繼承關(guān)系的類對象,去調(diào)用同一函數(shù),產(chǎn)生了不同的行為。
簡單的說:就是”一個接口多種實(shí)現(xiàn)“。

1.2為什么要用多態(tài)呢?

我們知道,封裝可以隱藏實(shí)現(xiàn)細(xì)節(jié),使得代碼模塊化;繼承可以擴(kuò)展已存在的代碼模塊(類);它們的目的都是為了代碼重用。而多態(tài)除了代碼的復(fù)用性外,還可以解決項目中緊偶合的問題,提高程序的可擴(kuò)展性.。耦合度講的是模塊與模塊之間,代碼與代碼之間的關(guān)聯(lián)度,通過對系統(tǒng)的分析把他分解成一個個的子模塊,子模塊提供穩(wěn)定的接口,達(dá)到降低系統(tǒng)耦合度的的目的,模塊與模塊之間盡量使用模塊接口訪問,而不是隨意引用其他模塊的成員變量。

1.3多態(tài)有什么好處?

1.應(yīng)用程序不必為每一個派生類編寫功能調(diào)用,只需要對抽象基類進(jìn)行處理即可。大大提高程序的可復(fù)用性。//繼承

2.派生類的功能可以被基類的方法或引用變量所調(diào)用,這叫向后兼容,可以提高可擴(kuò)充性和可維護(hù)性。 //多態(tài)的真正作用,

2.多態(tài)的定義及實(shí)現(xiàn)

2.1繼承中構(gòu)成多態(tài)的條件

1.必須通過基類的指針或者引用調(diào)用虛函數(shù)

2.被調(diào)用的函數(shù)必須是虛函數(shù),且派生類必須對基類的虛函數(shù)進(jìn)行重寫

在這里插入圖片描述

2.2虛函數(shù)

虛函數(shù):即被virtual修飾的類成員函數(shù)稱為虛函數(shù)。

class Person {
public:
	virtual void BuyTicket() { cout << "買票-全價" << endl;}
};

2.3虛函數(shù)的重寫

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

//void BuyTicket (),返回值類型、函數(shù)名字、參數(shù)列表完全相同
class Person {
public:
	virtual void BuyTicket() { cout << "買票-全價" << endl; }
};

class Student : public Person {
public:
	virtual void BuyTicket() { cout << "買票-半價" << endl; }
/*注意:在重寫基類虛函數(shù)時,派生類的虛函數(shù)在不加virtual關(guān)鍵字時,雖然也可以構(gòu)成重寫(因?yàn)槔^承后
基類的虛函數(shù)被繼承下來了在派生類依舊保持虛函數(shù)屬性),但是該種寫法不是很規(guī)范,不建議這樣使用*/
/*void BuyTicket() { cout << "買票-半價" << endl; }*/
};

虛函數(shù)重寫的兩個例外:

1.協(xié)變(基類與派生類虛函數(shù)返回值類型不同)

派生類重寫基類虛函數(shù)時,與基類虛函數(shù)返回值類型不同。即基類虛函數(shù)返回基類對象的指針或者引用,派生類虛函數(shù)返回派生類對象的指針或者引用時,稱為協(xié)變。

class Person {
public:
	virtual A* f() {return new A;}    //基類的返回值為A*
};

class Student : public Person {
public:
	virtual B* f() {return new B;}    //派生類的返回值為B*
};

2.析構(gòu)函數(shù)的重寫(基類與派生類析構(gòu)函數(shù)的名字不同)

如果基類的析構(gòu)函數(shù)為虛函數(shù),此時派生類析構(gòu)函數(shù)只要定義,無論是否加virtual關(guān)鍵字,都與基類的析構(gòu)函數(shù)構(gòu)成重寫,雖然析構(gòu)函數(shù)名字不同,看起來違背了重寫的規(guī)則,其實(shí)不然,這里可以理解為編譯器對析構(gòu)函數(shù)的名稱做了特殊處理,編譯后析構(gòu)函數(shù)的名稱統(tǒng)一處

理成destructor。

class Person {
public:
	virtual ~Person() {cout << "~Person()" << endl;}
};
class Student : public Person {
public:
	virtual ~Student() { cout << "~Student()" << endl; }
};
// 只有派生類Student的析構(gòu)函數(shù)重寫了Person的析構(gòu)函數(shù),下面的delete對象調(diào)用析構(gòu)函數(shù),才能構(gòu)成多態(tài),才能保證p1和p2指向的對象正確的調(diào)用析構(gòu)函數(shù)。
int main()
{
	Person* p1 = new Person;
	Person* p2 = new Student;
	delete p1;
	delete p2;
	return 0;
}

2.4C++11 override 和 final

C++11提供了override和final兩個關(guān)鍵字,可以幫助用戶檢測是否重寫。

1.final:修飾虛函數(shù),表示該虛函數(shù)不能再被重寫

class Car
{
public:
	virtual void Drive() final {}
};
class Benz :public Car
{
public:
	virtual void Drive() {cout << "Benz-舒適" << endl;}
};

2.override: 檢查派生類虛函數(shù)是否重寫了基類某個虛函數(shù),如果沒有重寫編譯報錯。

class Car{
public:
	virtual void Drive(){}
};
class Benz :public Car {
public:
	virtual void Drive() override {cout << "Benz-舒適" << endl;}
};

2.5 重載、覆蓋(重寫)、隱藏(重定義)的對比

在這里插入圖片描述

3.抽象類

3.1概念

在虛函數(shù)的后面寫上 =0 ,則這個函數(shù)為純虛函數(shù)。包含純虛函數(shù)的類叫做抽象類(也叫接口類),抽象類不能實(shí)例化出對象。派生類繼承后也不能實(shí)例化出對象,只有重寫純虛函數(shù),派生類才能實(shí)例化出對象。純虛函數(shù)規(guī)范了派生類必須重寫,另外純虛函數(shù)更體現(xiàn)出了接口繼承。

class Car
{
public:
	virtual void Drive() = 0;  //純虛函數(shù)
};
class Benz :public Car
{
public:
	virtual void Drive()
{
	cout << "Benz-舒適" << endl;
}
};
class BMW :public Car
{
public:
	virtual void Drive()
{
	cout << "BMW-操控" << endl;
}
};
void Test()
{
	Car* pBenz = new Benz;
	pBenz->Drive();
	Car* pBMW = new BMW;
	pBMW->Drive();
}

3.2實(shí)現(xiàn)繼承和接口繼承

普通函數(shù)的繼承是一種實(shí)現(xiàn)繼承,派生類繼承了基類函數(shù),可以使用函數(shù),繼承的是函數(shù)的實(shí)現(xiàn)。

虛函數(shù)的繼承是一種接口繼承,派生類繼承的是基類虛函數(shù)的接口,目的是為了重寫,達(dá)成多態(tài),繼承的是接口。所以如果不實(shí)現(xiàn)多態(tài),不要把函數(shù)定義成虛函數(shù)。

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

4.1虛函數(shù)表

// 這里??家坏拦P試題:sizeof(Base)是多少?
class Base
{
public:
	virtual void Func1()
	{
		cout << "Func1()" << endl;
	}
	private:
	int _b = 1;
};
int main()
	{	
		Base b;
		return 0;
	}

在這里插入圖片描述

通過觀察測試我們發(fā)現(xiàn)b對象是8bytes,除了_b成員,還多一個__vfptr,我們稱之為虛函數(shù)表指針(v代表virtual,f代表function)。一個含有虛函數(shù)的類中都至少有一個虛函數(shù)表指針,因?yàn)樘摵瘮?shù)的地址要被放到虛函數(shù)表中,虛函數(shù)表也簡稱虛表。

// 針對上面的代碼我們做出以下改造
// 1.我們增加一個派生類Derive去繼承Base
// 2.Derive中重寫Func1
// 3.Base再增加一個虛函數(shù)Func2和一個普通函數(shù)Func3
class Base  //基類
{
public:
	virtual void Func1()
	{
		cout << "Base::Func1()" << endl;
	}
	virtual void Func2()   //虛函數(shù)
	{
		cout << "Base::Func2()" << endl;
	}
	void Func3()   //普通函數(shù)
	{ 
		cout << "Base::Func3()" << endl;
	}
private:
	int _b = 1;
};
  
class Derive : public Base  //派生類
{
public:
	virtual void Func1()
	{
		cout << "Derive::Func1()" << endl;
	}
private:
	int _d = 2;
};

int main()
{
	Base b;
	Derive d;
	return 0;
}

在這里插入圖片描述

1.派生類對象d中也有一個虛表指針,d對象由兩部分構(gòu)成:父類繼承下來的成員和自己的成員。

2.基類b對象和派生類d對象虛表是不一樣的,這里我們發(fā)現(xiàn)Func1完成了重寫,所以d的虛表中存的是重寫的Derive::Func1,所以虛函數(shù)的重寫也叫作覆蓋,覆蓋就是指虛表中虛函數(shù)的覆蓋。重寫是語法的叫法,覆蓋是原理層的叫法。

3.另外Func2繼承下來后是虛函數(shù),所以放進(jìn)了虛表,F(xiàn)unc3也繼承下來了,但是不是虛函數(shù),所以不會放進(jìn)虛表。

4.虛函數(shù)表本質(zhì)是一個存虛函數(shù)指針的指針數(shù)組,一般情況這個數(shù)組最后面放了一個nullptr。

5.總結(jié)一下派生類的虛表生成:a.先將基類中的虛表內(nèi)容拷貝一份到派生類虛表中 b.如果派生類重寫了基類中某個虛函數(shù),用派生類自己的虛函數(shù)覆蓋虛表中基類的虛函數(shù) c.派生類自己新增加的虛函數(shù)按其在派生類中的聲明次序增加到派生類虛表的最后。

6.還有一個很容易混淆的問題:虛函數(shù)存在哪的?虛表存在哪的?

注意虛表存的是虛函數(shù)指針,不是虛函數(shù),虛函數(shù)和普通函數(shù)一樣的,都是存在代碼段的,只是他的指針又存到了虛表中。另外對象中存的不是虛表,存的是虛表指針。那么虛表存在哪的呢?

4.2多態(tài)的原理

1.觀察下圖的紅色箭頭我們看到,p是指向mike對象時,p->BuyTicket在mike的虛表中找到虛函數(shù)是Person::BuyTicket。

2.觀察下圖的藍(lán)色箭頭我們看到,p是指向johnson對象時,p->BuyTicket在johson的虛表中找到虛函數(shù)是Student::BuyTicket。

3.這樣就實(shí)現(xiàn)出了不同對象去完成同一行為時,展現(xiàn)出不同的形態(tài)。

4.反過來思考我們要達(dá)到多態(tài),有兩個條件,一個是虛函數(shù)覆蓋,一個是對象的指針或引用調(diào)用虛函數(shù)。

反思一下為什么?

5.再通過下面的匯編代碼分析,看出滿足多態(tài)以后的函數(shù)調(diào)用,不是在編譯時確定的,是運(yùn)行起來以后到對象的中取找的。不滿足多態(tài)的函數(shù)調(diào)用時編譯是確認(rèn)好的。

在這里插入圖片描述

4.3 動態(tài)綁定與靜態(tài)綁定

1.靜態(tài)綁定又稱為前期綁定(早綁定),在程序編譯期間確定了程序的行為,也稱為靜態(tài)多態(tài),比如:函數(shù)重載

2.動態(tài)綁定又稱后期綁定(晚綁定),是在程序運(yùn)行期間,根據(jù)具體拿到的類型確定程序的具體行為,調(diào)用具體的函數(shù),也稱為動態(tài)多態(tài)。

5.單繼承和多繼承關(guān)系的虛函數(shù)表

5.1 單繼承中的虛函數(shù)表

在這里插入圖片描述

5.2 多繼承中的虛函數(shù)表

多繼承派生類的未重寫的虛函數(shù)放在第一個繼承基類部分的虛函數(shù)表中

在這里插入圖片描述

總結(jié)

本篇文章就到這里了,希望能給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!

相關(guān)文章

  • C++實(shí)現(xiàn)區(qū)塊鏈的源碼

    C++實(shí)現(xiàn)區(qū)塊鏈的源碼

    這篇文章主要介紹了C++實(shí)現(xiàn)區(qū)塊鏈的源碼,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-01-01
  • C語言算法學(xué)習(xí)之雙向鏈表詳解

    C語言算法學(xué)習(xí)之雙向鏈表詳解

    雙向鏈表也叫雙鏈表,是鏈表的一種,它的每個數(shù)據(jù)結(jié)點(diǎn)中都有兩個指針,分別指向直接后繼和直接前驅(qū)。本文主要介紹了C語言算法中雙向鏈表的實(shí)現(xiàn),需要的可以參考一下
    2022-05-05
  • C++實(shí)現(xiàn)推箱子小項目

    C++實(shí)現(xiàn)推箱子小項目

    這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)推箱子小項目,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • 深入了解C語言結(jié)構(gòu)化的程序設(shè)計

    深入了解C語言結(jié)構(gòu)化的程序設(shè)計

    這篇文章主要介紹了C語言編程中程序的一些基本的編寫優(yōu)化技巧,文中涉及到了基礎(chǔ)的C程序內(nèi)存方面的知識,非常推薦!需要的朋友可以參考下
    2021-07-07
  • 深入剖析設(shè)計模式中的組合模式應(yīng)用及在C++中的實(shí)現(xiàn)

    深入剖析設(shè)計模式中的組合模式應(yīng)用及在C++中的實(shí)現(xiàn)

    這篇文章主要介紹了設(shè)計模式中的組合模式應(yīng)用及在C++中的實(shí)現(xiàn),組合模式可以清晰地反映出遞歸構(gòu)建樹狀的組合結(jié)構(gòu),需要的朋友可以參考下
    2016-03-03
  • C語言冒泡排序超全面實(shí)現(xiàn)流程

    C語言冒泡排序超全面實(shí)現(xiàn)流程

    算法中排序是十分重要的,而每一個學(xué)習(xí)計算機(jī)的都會在初期的時候接觸到這種排序,下面這篇文章主要給大家介紹了關(guān)于c語言冒泡排序的相關(guān)資料,需要的朋友可以參考下
    2023-01-01
  • C語言中常見的六種動態(tài)內(nèi)存錯誤總結(jié)

    C語言中常見的六種動態(tài)內(nèi)存錯誤總結(jié)

    學(xué)習(xí)過C語言中的動態(tài)內(nèi)存函數(shù),例如【malloc】、【calloc】、【realloc】、【free】,那它們在使用的過程中會碰到哪些問題呢,本本文我們一起來探討下,感興趣的朋友跟著小編一起來看看吧
    2023-11-11
  • C++?Qt開發(fā)之使用QNetworkAccessManager實(shí)現(xiàn)Web網(wǎng)頁訪問

    C++?Qt開發(fā)之使用QNetworkAccessManager實(shí)現(xiàn)Web網(wǎng)頁訪問

    Qt?是一個跨平臺C++圖形界面開發(fā)庫,利用Qt可以快速開發(fā)跨平臺窗體應(yīng)用程序,本文主要介紹了如何運(yùn)用QNetworkAccessManager組件實(shí)現(xiàn)Web網(wǎng)頁訪問,需要的可以參考下
    2024-03-03
  • C語言switch使用之詭異用法詳解

    C語言switch使用之詭異用法詳解

    今天小編就為大家分享一篇C語言switch使用之詭異用法詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-12-12
  • C++設(shè)計模式之工廠模式

    C++設(shè)計模式之工廠模式

    本文是C++設(shè)計模式系列文章的第一篇,主要給大家講述下工廠模式,非常的簡單實(shí)用,有需要的小伙伴可以參考下
    2016-05-05

最新評論