91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

C++的多態與虛函數是什么

發布時間:2022-03-28 09:07:43 來源:億速云 閱讀:117 作者:iii 欄目:開發技術

這篇文章主要介紹“C++的多態與虛函數是什么”的相關知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強,希望這篇“C++的多態與虛函數是什么”文章能幫助大家解決問題。

多態性

多態性是面向對象程序設計的關鍵技術之一,若程序設計語言不支持多態性,不能稱為面向對象的語言,利用多態性技術,可以調用同一個函數名的函數,實現完全不同的功能

在C++中有兩種多態性:

  • 編譯時的多態

通過函數的重載和運算符的重載來實現的

  • 運行時的多態性

運行時的多態性是指在程序執行前,無法根據函數名和參數來確定該調用哪一個函數,必須在程序執行過程中,根據執行的具體情況來動態地確定;它是通過類繼承關系public和虛函數來實現的,目的也是建立一種通用的程序;通用性是程序追求的主要目標之一

通過引用或指針調用時,才可以達到運行時的多態

虛函數

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

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

關鍵字virtual指明該成員函數為虛函數,virtual僅用于類定義中,如虛函數在類外定義,不可加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;
	}
};
 // 需要公有繼承 公有繼承代表是一個的意思
 // 需要引用或指針調用
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;
}

C++的多態與虛函數是什么

在這里我們可以看到,當我們調用fun()函數時,傳入dog對象則調用Dog的方法,傳入cat調用Cat方法;這就是所謂的運行時的多態

要想達到運行時的多態(晚綁定)需要滿足:

  • 公有繼承

  • 有虛函數

  • 必須以指針或引用方式調用虛函數

若發生早綁定,則會調用Animal類型的方法

成員函數應盡可能的設置為虛函數,但必須注意一下幾條:

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

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

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

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

5.內聯函數每個對象一個拷貝,無映射關系,不能作為虛函數

6.析構函數可定義為虛函數,構造函數不可以定義為虛函數,因為在調用構造函數時對象還沒有完成實例化;在基類中及其派生類中都動態分配的內存空間時,必須把析構函數定義為虛函數,實現撤銷對象時的多態性

7.函數執行速度要稍慢一些,為了實現多態性,每一個派生類中均要保存相應虛函數的入口地址表,函數的調用機制也是間接實現;所以多態性總要付出一定代價,但通用性是一個更高的目標

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

虛函數是覆蓋,同名函數是隱藏

虛函數編譯過程

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()
{	
}

C++的多態與虛函數是什么

此處虛函數表中進行的是同名覆蓋,而不像繼承關系中,同名成員進行隱藏,就近處理;虛函表僅有一份,存在數據區

在主函數創建對象

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

C++的多態與虛函數是什么

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

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

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

	op = &base;
	op->add(); //指針或引用調動,則采用運行時多態
	op->fun();
	op->print();

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

C++的多態與虛函數是什么

也就是我們通過,對象名.方法 的方式調用虛函數,則通過編譯時多態的方式

C++的多態與虛函數是什么

運行時的多態,是通過查詢虛表進行調用;下面通過匯編進一步查看

C++的多態與虛函數是什么

只有進行以指針調用或引用調用的時候才會對虛表進行查詢

三層繼承

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;
	}
};

C++的多態與虛函數是什么

我們可以看到虛函數表,當我們構建派生類,會復制基類的虛函數表,將虛表指針指向新的虛函數表,并且將同名的虛函數進行覆蓋

依舊使用上面代碼

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

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

C++的多態與虛函數是什么

這里依然屬于動態綁定,所以調用虛表指針指向的相對應類的虛表

關于“C++的多態與虛函數是什么”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識,可以關注億速云行業資訊頻道,小編每天都會為大家更新不同的知識點。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

c++
AI

台山市| 瓦房店市| 泰宁县| 招远市| 天祝| 喀喇沁旗| 阿拉善左旗| 桂阳县| 灵丘县| 资阳市| 上栗县| 天柱县| 海门市| 渝北区| 拜城县| 沈阳市| 民县| 横山县| 迁安市| 通化县| 安丘市| 宕昌县| 临汾市| 容城县| 和田县| 礼泉县| 嘉鱼县| 华容县| 鄂尔多斯市| 岱山县| 榆社县| 六枝特区| 定安县| 上高县| 长乐市| 龙胜| 资兴市| 察哈| 海林市| 乌鲁木齐市| 始兴县|