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

C++的多態(tài)與虛函數(shù)你了解嗎

 更新時間:2022年03月27日 15:07:58   作者:悲傷土豆拌飯  
這篇文章主要為大家詳細(xì)介紹了C++多態(tài)與虛函數(shù),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助

多態(tài)性

多態(tài)性是面向?qū)ο蟪绦蛟O(shè)計的關(guān)鍵技術(shù)之一,若程序設(shè)計語言不支持多態(tài)性,不能稱為面向?qū)ο蟮恼Z言,利用多態(tài)性技術(shù),可以調(diào)用同一個函數(shù)名的函數(shù),實現(xiàn)完全不同的功能

在C++中有兩種多態(tài)性:

  • 編譯時的多態(tài)

通過函數(shù)的重載和運(yùn)算符的重載來實現(xiàn)的

  • 運(yùn)行時的多態(tài)性

運(yùn)行時的多態(tài)性是指在程序執(zhí)行前,無法根據(jù)函數(shù)名和參數(shù)來確定該調(diào)用哪一個函數(shù),必須在程序執(zhí)行過程中,根據(jù)執(zhí)行的具體情況來動態(tài)地確定;它是通過類繼承關(guān)系public和虛函數(shù)來實現(xiàn)的,目的也是建立一種通用的程序;通用性是程序追求的主要目標(biāo)之一

通過引用或指針調(diào)用時,才可以達(dá)到運(yùn)行時的多態(tài)

虛函數(shù)

虛函數(shù)是一個類的成員函數(shù),定義格式如下:

virtual 返回類型 函數(shù)名(參數(shù)表);

關(guān)鍵字virtual指明該成員函數(shù)為虛函數(shù),virtual僅用于類定義中,如虛函數(shù)在類外定義,不可加virtual

我們來看下面代碼

class Animal
{
private:
	string name;
public:
	Animal(const string& na):name(na)
	{}
public:
	virtual void eat(){}
	virtual void walk(){}
	virtual void tail(){}
	virtual void PrintInfo(){}

	string& get_name()
	{
		return name;
	}
	const string& get_name()const
	{
		return name;
	}
};

class Dog :public Animal
{
private:
	string owner;
public:
	Dog(const string& ow, const string na) :Animal(na), owner(ow)
	{}
	virtual void eat() 
	{
		cout << "Dog Eat: bone" << endl;
	}
	virtual void walk() 
	{
		cout << "Dog Walk: run" << endl;
	}
	virtual void tail() 
	{
		cout << "Dog Tail: wangwang" << endl;
	}
	virtual void PrintInfo() 
	{
		cout << "Dog owner" << owner << endl;
		cout << "Dog name:" << get_name() << endl;
	}
};
class Cat :public Animal
{
private:
	string owner;
public:
	Cat(const string& ow, const string na) :Animal(na), owner(ow)
	{}
	virtual void eat()
	{
		cout << "Cat Eat: fish" << endl;
	}
	virtual void walk()
	{
		cout << "Cat Walk: silent" << endl;
	}
	virtual void tail()
	{
		cout << "Cat Tail: miaomiao" << endl;
	}
	virtual void PrintInfo()
	{
		cout << "Cat owner: " << owner << endl;
		cout << "Cat name: " << get_name() << endl;
	}
};
 // 需要公有繼承 公有繼承代表是一個的意思
 // 需要引用或指針調(diào)用
void fun(Animal& animal)
{
	animal.eat(); //對象名稱.虛方法()
	animal.walk();
	animal.tail();
	animal.PrintInfo();
}

int main()
{
	Dog dog("zyq", "hashiqi"); //const string& ow = "zyq"
	Cat cat("zyq", "bosimao");
	fun(dog);
	fun(cat);
	return 0;
}

在這里插入圖片描述

在這里我們可以看到,當(dāng)我們調(diào)用fun()函數(shù)時,傳入dog對象則調(diào)用Dog的方法,傳入cat調(diào)用Cat方法;這就是所謂的運(yùn)行時的多態(tài)

要想達(dá)到運(yùn)行時的多態(tài)(晚綁定)需要滿足:

  • 公有繼承
  • 有虛函數(shù)
  • 必須以指針或引用方式調(diào)用虛函數(shù)

若發(fā)生早綁定,則會調(diào)用Animal類型的方法

成員函數(shù)應(yīng)盡可能的設(shè)置為虛函數(shù),但必須注意一下幾條:

1.派生類中定義虛函數(shù)必須與基類中的虛函數(shù)同名外,還必須同參數(shù)表,同返回類型;否則被認(rèn)為是重載,而不是虛函數(shù)。如基類中返回基類指針,派生類中返回派生類指針是允許的,這是一個例外

2.只有類的成員函數(shù)才能說明為虛函數(shù),這是因為虛函數(shù)僅適用于有繼承關(guān)系的類對象

3.靜態(tài)成員函數(shù),是所有同一類對象公有,不受限于某個對象,不能作為虛函數(shù)(友元函數(shù)也不可以)

4.實現(xiàn)動態(tài)多態(tài)性時,必須使用基類類型的指針變量或引用,使該指針指向該基類的不同派生類的對象,并通過該指針指向虛函數(shù),才能實現(xiàn)動態(tài)的多態(tài)性

5.內(nèi)聯(lián)函數(shù)每個對象一個拷貝,無映射關(guān)系,不能作為虛函數(shù)

6.析構(gòu)函數(shù)可定義為虛函數(shù),構(gòu)造函數(shù)不可以定義為虛函數(shù),因為在調(diào)用構(gòu)造函數(shù)時對象還沒有完成實例化;在基類中及其派生類中都動態(tài)分配的內(nèi)存空間時,必須把析構(gòu)函數(shù)定義為虛函數(shù),實現(xiàn)撤銷對象時的多態(tài)性

7.函數(shù)執(zhí)行速度要稍慢一些,為了實現(xiàn)多態(tài)性,每一個派生類中均要保存相應(yīng)虛函數(shù)的入口地址表,函數(shù)的調(diào)用機(jī)制也是間接實現(xiàn);所以多態(tài)性總要付出一定代價,但通用性是一個更高的目標(biāo)

8.如果定義放在類外,virtual只能加在函數(shù)聲明前面,不能加載函數(shù)定義前面;正確的定義必須不包括virtual

虛函數(shù)是覆蓋,同名函數(shù)是隱藏

虛函數(shù)編譯過程

class Object
{
private:
	int value;
public:
	Object(int x = 0) :value(x)
	{}
	virtual void add()
	{
		cout << "Object::add" << endl;
	}
	virtual void fun()
	{
		cout << "Object::fun" << endl;
	}
	virtual void print()const
	{
		cout << "Object::print" << endl;
	}
};
class Base:public Object
{
private:
	int sum;
public:
	Base(int x = 0) :Object(x+10),sum(x)
	{}
	virtual void add()
	{
		cout << "Base::add" << endl;
	}
	virtual void fun()
	{
		cout << "Base::fun" << endl;
	}
	virtual void print()const
	{
		cout << "Base::print" << endl;
	}
};

int main()
{	
}

在這里插入圖片描述

此處虛函數(shù)表中進(jìn)行的是同名覆蓋,而不像繼承關(guān)系中,同名成員進(jìn)行隱藏,就近處理;虛函表僅有一份,存在數(shù)據(jù)區(qū)

在主函數(shù)創(chuàng)建對象

int main()
{
	Base base(10);
	Object* op = &base;
}

在這里插入圖片描述

可以看到base的大小為12字節(jié),因為其中基類對象Object,添加了虛表變?yōu)榱?字節(jié),且在構(gòu)建過程,首先構(gòu)建Object基類,此時虛表指針指向Object的虛表,而接著構(gòu)建Base類的時候,會將虛表指針修改為指向Base的虛表

也就是,當(dāng)有虛函數(shù)時,構(gòu)造函數(shù)除了構(gòu)建對象初始化對象的數(shù)據(jù)成員外,還會將虛表的地址給到虛表指針;同時這也是構(gòu)造函數(shù)不可以作為虛函數(shù)的原因

int main()
{
	Base base(10);
	Object* op = NULL;
	Object obj(0);

	op = &base;
	op->add(); //指針或引用調(diào)動,則采用運(yùn)行時多態(tài)
	op->fun();
	op->print();

	obj = base;
	obj.add(); //對象直接調(diào)動,則采用編譯時多態(tài)
	obj.fun();
	obj.print();
}

在這里插入圖片描述

也就是我們通過,對象名.方法 的方式調(diào)用虛函數(shù),則通過編譯時多態(tài)的方式

在這里插入圖片描述

運(yùn)行時的多態(tài),是通過查詢虛表進(jìn)行調(diào)用;下面通過匯編進(jìn)一步查看

在這里插入圖片描述

只有進(jìn)行以指針調(diào)用或引用調(diào)用的時候才會對虛表進(jìn)行查詢

三層繼承

class Object
{
private:
	int value;
public:
	Object(int x = 0) :value(x)
	{}
	virtual void add()
	{
		cout << "Object::add" << endl;
	}
	virtual void fun()
	{
		cout << "Object::fun" << endl;
	}
	virtual void print()const
	{
		cout << "Object::print" << endl;
	}

	void fn_a()
	{
		fun();	
	}
};
class Base:public Object
{
private:
	int sum;
public:
	Base(int x = 0) :Object(x+10),sum(x)
	{}
	virtual void add()
	{
		cout << "Base::add" << endl;
	}
	virtual void fun()
	{
		cout << "Base::fun" << endl;
	}
	virtual void show()
	{
		cout << "Base::show" << endl;
	}
};
class Test :public Base
{
private:
	int num;
public:
	Test(int x = 0) :Base(x + 10)
	{}
	virtual void add()
	{
		cout << "Test::add" << endl;
	}
	virtual void print() const
	{
		cout << "Test::print" << endl;
	}
	virtual void show()
	{
		cout << "Test::show" << endl;
	}
};

在這里插入圖片描述

我們可以看到虛函數(shù)表,當(dāng)我們構(gòu)建派生類,會復(fù)制基類的虛函數(shù)表,將虛表指針指向新的虛函數(shù)表,并且將同名的虛函數(shù)進(jìn)行覆蓋

依舊使用上面代碼

/*
	void fn_a()
	{
		fun();	//this->fun(); 屬于動態(tài)綁定!
	}
*/
int main()
{
	Test t1;
	Base base;
	Object obj;

	t1.fn_a(); //fn_a(&t1);
	base.fun_a();
	obj.fn_a();
	return 0;
}

在這里插入圖片描述

這里依然屬于動態(tài)綁定,所以調(diào)用虛表指針指向的相對應(yīng)類的虛表

總結(jié)

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

相關(guān)文章

  • VS2019 Nuget找不到包的問題處理

    VS2019 Nuget找不到包的問題處理

    這篇文章主要介紹了VS2019 Nuget找不到包的問題處理,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-03-03
  • Python繪圖之詳解matplotlib

    Python繪圖之詳解matplotlib

    這篇文章主要介紹了Python繪圖之詳解matplotlib,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • VS2010/MFC編程(常用控件:樹形控件Tree Control控件創(chuàng)建h和實例)

    VS2010/MFC編程(常用控件:樹形控件Tree Control控件創(chuàng)建h和實例)

    本篇文章介紹了VS2010/MFC編程:常用控件:樹形控件Tree Control,包括樹形控件的創(chuàng)建、CTreeCtrl類的主要成員函數(shù)和應(yīng)用實例有興趣的可以了解一下。
    2016-12-12
  • C語言中用棧+隊列實現(xiàn)隊列中的元素逆置

    C語言中用棧+隊列實現(xiàn)隊列中的元素逆置

    這篇文章主要介紹了C語言中用利用棧和隊列實現(xiàn)隊列中的元素逆置的相關(guān)資料,對正在學(xué)習(xí)的小伙伴有一定的參考價值,需要的可以參考一下,希望對你有所幫助
    2022-02-02
  • 利用C++11原子量如何實現(xiàn)自旋鎖詳解

    利用C++11原子量如何實現(xiàn)自旋鎖詳解

    當(dāng)自旋鎖嘗試獲取鎖時以忙等待(busy waiting)的形式不斷地循環(huán)檢查鎖是否可用,下面這篇文章主要給大家介紹了關(guān)于利用C++11原子量如何實現(xiàn)自旋鎖的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2018-06-06
  • C++11標(biāo)準(zhǔn)庫bind函數(shù)應(yīng)用教程

    C++11標(biāo)準(zhǔn)庫bind函數(shù)應(yīng)用教程

    bind函數(shù)定義在頭文件functional中,可以將bind函數(shù)看做成一個通用的函數(shù)適配器,他接收一個可調(diào)用對象,生成一個新的可調(diào)用對象來"適應(yīng)"原對象的參數(shù)列表。本文將帶大家詳細(xì)了解一下bind函數(shù)的應(yīng)用詳解
    2021-12-12
  • C語言 數(shù)據(jù)結(jié)構(gòu)堆排序順序存儲(升序)

    C語言 數(shù)據(jù)結(jié)構(gòu)堆排序順序存儲(升序)

    這篇文章主要介紹了C語言 數(shù)據(jù)結(jié)構(gòu)堆排序順序存儲(升序)的相關(guān)資料,需要的朋友可以參考下
    2017-05-05
  • 如何利用C語言實現(xiàn)最簡單的HTTP服務(wù)器詳解

    如何利用C語言實現(xiàn)最簡單的HTTP服務(wù)器詳解

    這篇文章主要給大家介紹了關(guān)于如何利用C語言實現(xiàn)最簡單的HTTP服務(wù)器的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用C語言具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-11-11
  • 數(shù)據(jù)結(jié)構(gòu)之?dāng)?shù)組翻轉(zhuǎn)的實現(xiàn)方法

    數(shù)據(jù)結(jié)構(gòu)之?dāng)?shù)組翻轉(zhuǎn)的實現(xiàn)方法

    這篇文章主要介紹了數(shù)據(jù)結(jié)構(gòu)之?dāng)?shù)組翻轉(zhuǎn)的實現(xiàn)方法的相關(guān)資料,這里用幾種實現(xiàn)方法來實現(xiàn)這樣的功能,需要的朋友可以參考下
    2017-10-10
  • 詳解C語言編程中的函數(shù)指針以及函數(shù)回調(diào)

    詳解C語言編程中的函數(shù)指針以及函數(shù)回調(diào)

    這篇文章主要介紹了C語言編程中的函數(shù)指針以及函數(shù)回調(diào),函數(shù)回調(diào)實際上就是讓函數(shù)指針作函數(shù)參數(shù)、調(diào)用時傳入函數(shù)地址,需要的朋友可以參考下
    2016-04-04

最新評論