C++學習筆記 —— 多態

什麼是多態

父類引用或者指針指向子類對象。

編譯時多態(靜態連編):函數和運算符重載。編譯階段就確定了地址。
運行時多態(動態連編):通常說的多態。

多態的使用

使用條件:

  1. 父類中函數爲虛函數
  2. 子類繼承父類並重寫該虛函數,子類virtual可寫可不寫
  3. 父類指針或引用指向子類對象,然後調用方法。

靜態連編

#include <iostream>

using namespace std;

class Animal

{
public:
	void speak()
	{
		cout << "動物" << endl;
	}
};

class Cat : public Animal
{
public:
	//子類重寫父類方法
	void speak() //子類中virtual可寫可不寫
	{
		cout << "小貓" << endl;
	}
};

void doSpeak(Animal &animal){
	animal.speak();
}
int main()
{
	Cat cat;//創建cat對象並傳入方法,cat是animal的子類,所以可以認爲cat是animal的一種類型
	//所以可以把cat傳進去
	doSpeak(cat);//動物  但是這裏調用的還是父類的方法,因爲沒有產生多態,是靜態編譯,只有用virtual才能產生多態
	Animal &a1 = cat1;
	a1.speak();//動物

	Animal *a2 = new Cat;
	a2->speak();//動物
}

動態連編

#include <iostream>

using namespace std;

class Animal

{
public:
	void virtual speak()
	{
		cout << "動物" << endl;
	}
};

class Cat : public Animal
{
public:
	//子類重寫父類方法
	void speak()
	{
		cout << "小貓" << endl;
	}
};

void doSpeak(Animal &animal){
	animal.speak();
}
int main()
{
	Cat cat1;
	doSpeak(cat1);//小貓 使用了virtual所以爲動態連編,爲多態

	Animal &a1 = cat1;
	a1.speak();//小貓

	Animal *a2 = new Cat;
	a2->speak();//小貓	
}

多態的好處

C++ 什麼是多態,多態的用途

Animal *a2 = new Cat;
a2->speak();//小貓	

比如這句話,我們可以根據我們的需要來創建不同對象,我們可以創建小貓,小狗,小豬,然後把它給animal。然後animal調用speak就可以實現多態,也就是根據創建的不同對象調用不同對象中的speak方法。“一個接口,多種方法”,程序在運行時才決定調用的函數。接口重用。

代碼的原則:修改關閉,擴展開放。

計算器例子

#include <iostream>

using namespace std;

class Calculator
{
public:
	int v1;
	int v2;
	void setv1(int v)
	{
		v1 = v;
	}
	void setv2(int v)
	{
		v2 = v;
	}
	int virtual getResult()
	{
		return v1 + v2;
	}
};

class PlusCalculator : public Calculator
{
	int virtual getResult()
	{
		return v1 + v2;
	}
};

class SubCalculator : public Calculator
{
	int virtual getResult()
	{
		return v1 - v2;
	}
};

int main()
{
	Calculator *calculator;
	//使用加法計算器
	calculator = new PlusCalculator;
	calculator->setv1(10);
	calculator->setv2(20);
	cout << calculator->getResult() << endl; //30

	delete calculator; //清除

	//使用減法計算器
	calculator = new SubCalculator;
	calculator->setv1(10);
	calculator->setv2(20);
	cout << calculator->getResult() << endl;

}

如果我們需要繼續擴展添加乘法計算器,就直接添加,使用的方式和上面一樣,擴展非常方便。這就是多態的好處。結構性好,可讀性高。
C++比C語言效率低,其實就是在多態上,因爲內部結構複雜了,就比c語言低一點點。

純虛函數和抽象類

接着上面的例子,我們可以把父類的函數作爲一個純虛函數。作用和上面一樣實現多態。

  1. 當一個類有純虛函數時,這個類就爲抽象類,不能實例化。
  2. 子類必須重寫實現所有純虛函數,不然子類也是一個抽象類,不能實例化。
class Calculator
{
public:
	int v1;
	int v2;
	void setv1(int v)
	{
		v1 = v;
	}
	void setv2(int v)
	{
		v2 = v;
	}
	//純虛函數:子類必須重寫此函數
	//這個類爲抽象類,該類無法實例化;
	int virtual getResult() = 0; 
};

虛析構和純虛析構

當我們繼承的時候,父類指針指向子類對象,然後釋放父類,則只創建了子類對象,而沒有釋放子類對象。這樣會導致釋放不乾淨內存問題。

#include <iostream>

using namespace std;

class Calculator
{
public:
	Calculator()
	{
		cout << "計算器構造" << endl;
	}
	~Calculator()
	{
		cout << "計算器析構" << endl;
	}
};

class PlusCalculator : public Calculator
{
public:
	PlusCalculator()
	{
		cout << "加法計算器構造" << endl;
	}
	~PlusCalculator()
	{
		cout << "加法計算器析構" << endl;
	}
};

int main()
{
	Calculator *calculator;
	//使用加法計算器
	calculator = new PlusCalculator;

	delete calculator; 
}
/*
計算器構造
加法計算器構造
計算器析構
*/

解決問題:使用虛析構

#include <iostream>

using namespace std;

class Calculator
{
public:
	Calculator()
	{
		cout << "計算器構造" << endl;
	}
	virtual ~Calculator()
	{
		cout << "計算器析構" << endl;
	}
};

class PlusCalculator : public Calculator
{
public:
	PlusCalculator()
	{
		cout << "加法計算器構造" << endl;
	}
	virtual ~PlusCalculator()
	{
		cout << "加法計算器析構" << endl;
	}
};

int main()
{
	Calculator *calculator;
	//使用加法計算器
	calculator = new PlusCalculator;

	delete calculator; 
}
/*
計算器構造
加法計算器構造
加法計算器析構
計算器析構
*/

虛析構也可以定義爲純虛析構,但是需要類內聲明,類外必須實現,如果析構函數爲純虛析構,則該類爲抽象類,不能實例化。
也就是說如果析構函數是純虛析構則該類肯定爲抽象類。

向上轉型和向下轉型

向下轉型

父類轉爲子類,叫做向下轉型,是不安全的。
因爲子類東西多,父類東西少,父類轉爲子類是不安全的。

Animal *animal = new Animal;
Cat *cat = (Cat*) animal; // 把父類轉爲子類

向上轉型

子類轉爲父類,是安全的,向上轉型,父類東西少,是安全的。

Cat *cat = new Cat;
Animal *animal = (Animal*) cat; // 把父類轉爲子類

發生了多態

如果發生類多態,則向下轉換也是安全的。

Animal *animal = new Cat;
Cat *cat = (Cat*) animal;
發佈了96 篇原創文章 · 獲贊 89 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章