日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

C++類和對象之多態詳解_C 語言

作者:燼燼今天學習了嗎 ? 更新時間: 2022-03-12 編程語言

多態基本概念和原理剖析

多態:多態是C++面向對象的三大特性之一。多態分為靜態多態和動態多態。
靜態多態:函數重載和運算符重載屬于靜態多態,復用函數名。
動態多態:派生類和虛函數實現運行時多態。

區別:
靜態多態的函數地址早綁定,編譯階段確定函數地址。
動態多態的函數地址晚綁定,運行階段確定函數地址。

#include <iostream>
using namespace std;
//動態多態滿足條件
//1、有繼承關系
//2、子類重寫父類的虛函數 重寫是指返回值 函數名 參數完全一樣    重載是指函數名相同
//動態多態使用
//父類的指針或引用,指向子類對象


//當子類重寫父類的虛函數,子類中的虛函數表內部會替換成子類的虛函數地址,將&Animal::speak替換成&Cat::speak

//動物類
class Animal {
public:
	//虛函數
	virtual void speak(){
		cout << "動物在說話" << endl;
	}
};
//貓類
class Cat :public Animal {
public:
	void speak() {
		cout << "小貓在說話" << endl;
	}
};
//狗類
class Dog :public Animal {
public:
	void speak() {
		cout << "小狗在說話" << endl;
	}
};

//執行說話的函數
//地址早綁定,在編譯階段就確定了函數的地址
//雖然想讓貓說話,但是這里輸出了動物在說話   因為地址早綁定
//如果想讓貓說話,這個函數的地址就不能提前綁定,需要在運行階段進行綁定,也即地址晚綁定
void DoSpeak(Animal &animal) {
	animal.speak();
}
void test01() {
	Cat cat;
	DoSpeak(cat);     //雖然想讓貓說話,但是這里輸出了動物在說話,因為地址早綁定,若父類改為虛函數地址晚綁定,就是貓在說話
	Dog dog;
	DoSpeak(dog);
}

void test02() {
	cout << "size of Animal = " << sizeof(Animal) << endl;
}
int main() {
	//test01();
	test02();
	system("pause");
	return 0;
}

多態案例1 計算器類

分別使用普通寫法和多態技術,設計實現兩個操作數進行運算的計算器類。

多態優點
1、代碼組織結構清晰
2、可讀性強
3、便于前期和后期的擴展與維護

#include<iostream>
using namespace std;

//普通寫法
class Calculate {
public:
	int GetResult(string oper) {
		if (oper == "+") {
			return num1 + num2;
		}
		else if (oper == "-") {
			return num1 - num2;
		}
		else if (oper == "*") {
			return num1 * num2;
		}
		//如果想擴展新的功能,需要修改原碼,在實際開發中,提倡開閉原則:對擴展進行開發,對修改進行關閉
	}
	int num1;
	int num2;
};
void test01() {
	//創建計算器對象
	Calculate c;
	c.num1 = 10;
	c.num2 = 10;
	cout << c.num1 << " + "<< c.num2 << " = " <<c.GetResult("+") << endl;
	cout << c.num1 << " - "<< c.num2 << " = " <<c.GetResult("-") << endl;
	cout << c.num1 << " * "<< c.num2 << " = " <<c.GetResult("*") << endl;
}


//利用多態實現計算器
//多態的優點
//1、組織結構清晰
//2、可讀性強
//3、對于前期擴展和后期維護性能高

//實現計算器抽象類
class AbstractCalculate {
public:
	virtual int Result() {
		return 0;
	}
	int m_num1;
	int m_num2;
};
//加法計算器類
class AddCalculate : public AbstractCalculate{
public:
	int Result() {
		return m_num1 + m_num2;
	}
};
//減法計算器類
class SubCalculate : public AbstractCalculate {
public:
	int Result() {
		return m_num1 - m_num2;
	}
};
//乘法計算器類
class MulCalculate : public AbstractCalculate {
public:
	int Result() {
		return m_num1 * m_num2;
	}
};
void test02() {
	//多態使用指針
	//父類指針或者引用指向子類對象

	//加法運算
	AbstractCalculate* p = new AddCalculate;
	p->m_num1 = 100;
	p->m_num2 = 100;
	cout << p->m_num1 << " + " << p->m_num2 << " = " << p->Result() <<endl;
	//用完后釋放新開辟的堆區數據
	delete p;

	//減法運算
	p = new SubCalculate;
	p->m_num1 = 100;
	p->m_num2 = 100;
	cout << p->m_num1 << " - " << p->m_num2 << " = " << p->Result() << endl;
	delete p;

	//乘法運算
	p = new MulCalculate;
	p->m_num1 = 100;
	p->m_num2 = 100;
	cout << p->m_num1 << " * " << p->m_num2 << " = " << p->Result() << endl;
	delete p;
}
int main() {
	//test01();
	test02();
	system("pause");
	return 0;
}

純虛函數和抽象類

在多態中,通常父類函數的虛函數是無意義的,主要都是調用子類重寫的內容。因此可以將虛函數改為純虛函數。當類中有了純虛函數,這個類也稱為抽象類。
.
抽象類特點:無法實例化對象;子類必須重新抽象類中的純虛函數,否則也屬于抽象類。

#include<iostream>
using namespace std;
//純虛函數語法 virtual 返回值 函數名(參數列表) = 0;
//當類中有了純虛函數,這個類也稱為抽象類,抽象類不能實例化對象,子類必須重寫抽象類里的純虛函數,不然子類也屬于抽象類
class Base {
public:
	//純虛函數 只要有純虛函數這個類就是抽象類
	virtual void func() = 0;
};
class Son :public Base {
public:
	void func() {
		cout << "Son類下的func函數調用" << endl;
	}
};
void test01() {
	/*抽象類是無法實例化對象的
	Base b;
	new Base;*/
	Son s;
	s.func();
	//多態方式調用 父類的指針new一個子類
	Base* p = new Son;
	p->func();
	delete p;
}

int main() {
	test01();
	system("pause");
	return 0;
}

多態案例2 制作飲品

利用多態技術實現制作飲品的流程,提供抽象制作飲品基類,提供子類制作咖啡和茶。

這里使用指針多態而不是引用的原因在于,引用需先實例化對象,但是有純虛函數的抽象類無法實例化對象。

#include<iostream>
using namespace std;
class AbstractDrinking {
public:
	//煮水
	virtual void Boil() = 0;
	//沖泡
	virtual void Brew() = 0;
	//倒入杯中
	virtual void DropInCup() = 0;
	//加入輔料
	virtual void AddSomething() = 0;

	//制作飲品
	void MakeDrink() {
		Boil();
		Brew();
		DropInCup();
		AddSomething();
	}
};

//制作咖啡流程
class Coffee : public AbstractDrinking {
public:
	//煮水
	virtual void Boil() {
		cout << "煮一壺沸水" << endl;
	}
	//沖泡
	virtual void Brew() {
		cout << "沖泡咖啡粉" << endl;
	}
	//倒入杯中
	virtual void DropInCup() {
		cout << "將咖啡倒入杯中" << endl;
	}
	//加入輔料
	virtual void AddSomething() {
		cout << "將牛奶和白糖加入咖啡中" << endl;
	}
};


//制作茶水流程
class Tea : public AbstractDrinking {
public:
	//煮水
	virtual void Boil() {
		cout << "煮一壺沸水" << endl;
	}
	//沖泡
	virtual void Brew() {
		cout << "沖泡西湖龍井" << endl;
	}
	//倒入杯中
	virtual void DropInCup() {
		cout << "將茶水倒入杯中" << endl;
	}
	//加入輔料
	virtual void AddSomething() {
		cout << "將枸杞加入茶水中" << endl;
	}
};

//制作飲品函數
void DoWork(AbstractDrinking *p) {   //這里相當于 AbstractDrinking *p = new Coffee;
	                                //若這里不使用指針,改為引用,test01的函數就不能使用
	                               //因為引用是先實例化對象再調用對象,抽象類無法實例化對象
	p->MakeDrink();
	delete p;  //防止內存泄露,使用后記得釋放內存
}
void test01() {
	//想喝一杯咖啡
	DoWork(new Coffee);
	cout << "-----------------------------------" << endl;
	//想喝一杯西湖龍井茶
	DoWork(new Tea);
}

int main() {
	test01();
	system("pause");
	return 0;
}

虛析構和純虛析構

使用多態技術時,如果有子類開辟到堆區,那么父類指針在釋放時無法調用到子類的析構代碼。解決該問題的方法是將父類中的析構函數改為虛析構或者純虛析構

虛析構和純虛析構共性
1、可以解決父類指針釋放子類對象
2、都需要有具體的函數實現
虛析構和純虛析構區別
如果是純虛析構,該類屬于抽象類,無法實例化對象。

#include<iostream>
#include<string>
using namespace std;
//動物類
class Animal {
public:
	Animal() {
		cout << "這是Animal的構造函數調用" << endl;
	}
	//純虛函數
	virtual void Speak() = 0;

	//為了走子類的虛構函數,需要將父類的虛構函數改為虛析構
	/*virtual ~Animal() {
		cout << "這是Animal的析構函數調用" << endl;
	}*/
	//純虛析構函數  父類的堆區可能也被開辟需要釋放,因此父類的析構也必須需要聲明,也需要實現
	//有純虛析構后這個類也屬于抽象類,無法實例化對象
	virtual ~Animal() = 0;
};
Animal:: ~Animal() {
	cout << "這是Animal類的寫在外部的純虛析構函數調用" << endl;
}

//貓類
class Cat : public Animal{
public:
	//Cat類的構造函數
	Cat(string name) {
		cout << "這是Cat類的構造函數" << endl;
		m_name = new string(name);
	}
	void Speak() {
		cout << *m_name<<"小貓的叫聲" << endl;
	}
	~Cat() {
		if (m_name != NULL) {
			//父類指針在析構的時候,不會調用子類中的析構函數,導致子類中有堆區開辟的數據沒有被釋放干凈導致內存泄露
			cout << "這是Cat類的析構函數" << endl;
			delete m_name;
			m_name = NULL;
		}
	}
	string *m_name;
	
};

void test01() {
	Animal* p = new Cat("Tom");             //如果子類中沒有堆區數據,可以不寫虛析構或純虛析構函數
	p->Speak();
	delete p;     //堆區開辟以后,釋放指針
}

int main() {
	test01();
	system("pause");
	return 0;
}

多態案例3 電腦組裝

電腦主要部件為CPU,顯卡和內存條。將每個零件封裝出抽象基類,并提供不同的廠商生產不同的零件。創建電腦類提供讓電腦工作的函數,并且調用每個零件工作的接口。測試時組裝三臺不同的電腦進行工作。

#include<iostream>
using namespace std;
//每個零件都封裝出抽象的基類
//CPU類
class Cpu {
public:
	//抽象的計算函數
	virtual void Calculate() = 0;
	//virtual ~Cpu() = 0; 
};
//Cpu::~Cpu() {
//	cout << "Cpu類寫在外部的純虛析構函數調用" << endl;
//}
//顯卡類
class VideoCard {
public:
	//抽象的顯示函數
	virtual void Display() = 0;
};
//內存條類
class Memory {
public:
	//抽象的存儲函數
	virtual void Storage() = 0;
};


//電腦類
class Computer {
public:
	Computer(Cpu* cpu, VideoCard* videocard, Memory* memory) {
		m_cpu = cpu;
		m_videocard = videocard;
		m_memory = memory;
	}
	//工作函數:讓零件調用起來的工作接口  父類指針調用接口時就已經是多態技術了
	void DoWork() {
		//Cpu進行計算操作
		m_cpu->Calculate();
		//顯卡進行顯示操作
		m_videocard->Display();
		//內存條進行存儲操作
		m_memory->Storage();
	}
	//提供析構函數釋放電腦的三個零件
	~Computer() {
		if (m_cpu != NULL) {
			delete m_cpu;
			m_cpu = NULL;
		}
		if (m_videocard != NULL) {
			delete m_videocard;
			m_videocard = NULL;
		}
		if (m_memory != NULL) {
			delete m_memory;
			m_memory = NULL;
		}
	}
private:
	Cpu *m_cpu;
	VideoCard *m_videocard;
	Memory *m_memory;
};


//具體廠商///
//因特爾廠商
class IntelCpu :public Cpu{
public:
	//子類重寫父類的虛函數
	virtual void Calculate() {
		cout << "Intel的Cpu開始計算了!" << endl;
	}
	/*~IntelCpu() {
		cout << "這是子類IntelCpu的析構函數調用" << endl;
	}*/
};
class IntelVideoCard :public VideoCard {
public:
	//子類重寫父類的虛函數
	virtual void Display() {
		cout << "Intel的顯卡開始顯示屏幕了!" << endl;
	}
};
class IntelMemory :public Memory {
public:
	//子類重寫父類的虛函數
	virtual void Storage() {
		cout << "Intel的內存條開始存儲數據了!" << endl;
	}
};

//Lenovo廠商
class LenovoCpu :public Cpu {
public:
	//子類重寫父類的虛函數
	virtual void Calculate() {
		cout << "Lenovo的Cpu開始計算了!" << endl;
	}
};
class LenovoVideoCard :public VideoCard {
public:
	//子類重寫父類的虛函數
	virtual void Display() {
		cout << "Lenovo的顯卡開始顯示屏幕了!" << endl;
	}
};
class LenovoMemory :public Memory {
public:
	//子類重寫父類的虛函數
	virtual void Storage() {
		cout << "Lenovo的內存條開始存儲數據了!" << endl;
	}
};


//開始測試,組裝不同的電腦
void test01() {
	//第一臺電腦的零件
	//父類指針指向了子類對象,利用了多態技術
	Cpu* intelcpu = new IntelCpu;
	VideoCard* intelvideocard = new IntelVideoCard;
	Memory* intelmemory = new IntelMemory;
	//創建第一臺電腦
	cout << "組裝好的第一臺電腦配置如下:" << endl;
	Computer* computer1 = new Computer(intelcpu,intelvideocard,intelmemory);
	computer1->DoWork();
	delete computer1;

	//創建第二臺電腦
	cout << "組裝好的第二臺電腦配置如下:" << endl;
	Computer* computer2 = new Computer(new LenovoCpu, new LenovoVideoCard, new LenovoMemory);
	computer2->DoWork();
	delete computer2;

	//創建第三臺電腦
	cout << "組裝好的第三臺電腦配置如下:" << endl;
	Computer* computer3 = new Computer(new LenovoCpu, new IntelVideoCard, new LenovoMemory);
	computer3->DoWork();
	delete computer3;

}

int main() {
	test01();
	system("pause");
	return 0;
}

原文鏈接:https://blog.csdn.net/weixin_44884304/article/details/122066349

欄目分類
最近更新