第八課c++多態

多態
如果父類指針指向的是父類對象則調用父類中定義的函數
如果父類指針指向的是子類對象則調用子類中定義的重寫函數
在這裏插入圖片描述
先看看如果不進行多態的實驗

#include <cstdlib>
#include <iostream>
using namespace std;
class Parent
{
public:
	 void print()
	{
		cout<<"Parent:print() do..."<<endl;
	}
};
class Child : public Parent
{
public:
	 void print()
	{
		cout<<"Child:print() do..."<<endl;
	}
};
int main()
{
	Child child;
	Parent *p = NULL;
	p = &child;
	p->print();
	child.print();
	system("pause");
	return 0;
}

在這裏插入圖片描述
上面的例子,雖然把派生類的地址傳給了基類的指針,但是執行相同函數的話,還是執行了父類指針裏面的函數。

接下來看多態的實現

#include <cstdlib>
#include <iostream>
using namespace std;

class Parent
{
public:
	virtual void print() //那個函數需要進行多態的話,就得添加virtual
	{
		cout<<"Parent:print() do..."<<endl;
	}
};

class Child : public Parent
{
public:
	virtual void print()//那個函數需要進行多態的話,就得添加virtual
	{
		cout<<"Child:print() do..."<<endl;
	}
};

int main()
{
	Child child;
	Parent parent;
	Parent *p = NULL;
	p = &child;
	p->print();
	p = &parent;
	p->print();
	system("pause");
	return 0;
}

在這裏插入圖片描述
進行多態的三個條件:
1)繼承 2)虛函數 3)父類指針或者引用


多態的實現原理
 當類中聲明虛函數時,編譯器會在類中生成一個虛函數表
 虛函數表是一個存儲類成員函數指針的數據結構
 虛函數表是由編譯器自動生成與維護的
 virtual成員函數會被編譯器放入虛函數表中
 當存在虛函數時,每個對象中都有一個指向虛函數表的指針(C++編譯器給父類對象、子類對象提前佈局vptr指針;當進行howToPrint(Parent *base)函數是,C++編譯器不需要區分子類對象或者父類對象,只需要再base指針中,找vptr指針即可。)
 VPTR一般作爲類對象的第一個成員

在這裏插入圖片描述
在這裏插入圖片描述
虛析構函數
當用new申請一個派生類的地址賦值給父類指針,當這個變量出了定義域的範圍之後,是不會執行派生類的析構函數的,只有對析構函數定義成虛函數纔行。
例如:

#include <cstdlib>
#include <iostream>
using namespace std;

class Parent
{
public:
	virtual void print() 
	{
		cout << "Parent:print() do..." << endl;
	}
	~Parent(){
		printf("我是父類析構函數\n");
	}
};

class Child : public Parent
{
public:
	virtual void print()
	{
		cout << "Child:print() do..." << endl;
	}
	~Child(){
		printf("我是子類析構函數\n");
	}
};

int main()
{
	
	Parent *p = new(Child);
	delete p;
	system("pause");
	return 0;
}

在這裏插入圖片描述

加了virtual之後

#include <cstdlib>
#include <iostream>
using namespace std;

class Parent
{
public:
	virtual void print() 
	{
		cout << "Parent:print() do..." << endl;
	}
	virtual ~Parent(){
		printf("我是父類析構函數\n");
	}
};

class Child : public Parent
{
public:
	virtual void print()
	{
		cout << "Child:print() do..." << endl;
	}
	virtual ~Child(){
		printf("我是子類析構函數\n");
	}
};

int main()
{
	
	Parent *p = new(Child);
	delete p;
	system("pause");
	return 0;
}

在這裏插入圖片描述
先執行派生類的析構函數,再執行父類的析構函數,這就正常了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章