天天看點

C++ 核心 4.7 多态

4.7 多态

多态的基本概念

靜态多态:函數重載和運算符重載。

動态多态:派生類和虛函數實作運作時多态。

差別:

靜态多态函數位址綁定,編譯階段确定函數位址。

動态多态的函數位址晚綁定,運作階段确定函數位址。

class Animal
{
public:
    void speak(){
        cout<<"動物在說話"<<endl;
    }
};

class Cat: public Animal{
public: 
    void speak(){
        cout<<"小貓在說話"<<endl;
    }
};
class Dog: public Animal{
public: 
    void speak(){
        cout<<"小狗在說話"<<endl;
    }
};
//早綁定,綁定到Animal的speak方法。
//傳入貓時,也是指向Animal的speak,輸出動物在說話。
void doSpeak(Animal &animal){
    animal.speak();
}
void test(){
    Cat cat;
    doSpeak(cat);
    Dog dot;
    doSpeak(dog);
}
           

而我們想要的效果是傳入貓時,輸出貓在說話。

隻要在Animal的方法

void speak()

前加上virtual關鍵字,變為

virtual void speak()

,就改寫為了虛函數。

虛函數就會在運作時确定函數位址。

總結:

動态多态滿足條件:

  1. 子類繼承父類
  2. 子類重寫父類的虛函數

    (注意,重寫不是重載,重寫的傳回值、函數名、參數清單都相同)

動态多态的使用

父類的指針(或引用)指向子類的對象。

多态的原理

有虛函數的類會有一個vfptr (虛函數表指針),指向虛函數表。

虛函數表記錄的是函數的入口位址。

子類繼承父類,重寫父類的虛函數後,改寫了自己的虛函數表。

4.7.2 多态案例1——電腦

class AbstractCalculator
{
public :
    virtual int getResult(){
        return 0;
    }
    int num1;
    int num2;
};
class AddCalculator: public AbstractCalculator
{
public :
    int getResult(){
        return num1 + num2;
    }
};

class SubCalculator: public AbstractCalculator
{
public :
    int getResult(){
        return num1 - num2;
    }
};


void test(){
    AbstarctCalculator * abc =  new AddCalculator;
    abc->num1 = 10;
    abc->num2 = 10;
    cout<<abc.getResult()<<endl;

    abc =  new SubCalculator;
    abc->num1 = 10;
    abc->num2 = 10;
    cout<<abc.getResult()<<endl;

}

           

好處:開閉原則

開發擴充,關閉修改。

在開發新功能時,不需要修改原來的代碼。

4.7.3 純虛函數和抽象類

有些函數永遠不會被真正的執行,不需要函數體。我們可以寫成純虛函數。

純虛函數

文法:在虛函數後面加=0;

virtual 傳回值類型 函數名(參數清單) = 0;

有純虛函數的類是抽象類。

抽象類無法執行個體化對象。

抽象類子類必須重寫抽象類的純虛函數,否則也是抽象類。

4.7.4 多态案例2-制作飲料

制作飲料的大緻流程是:煮水-沖泡-倒入杯中-加入輔料

利用多态實作這個抽象過程,然後實作子類分别制作咖啡和茶葉。

class AbstractDrinking{
public:
    virtual void Boil() = 0;
    virtual void Brew() = 0;
    virtual void PourInCup() = 0;
    virtual void PutSomething() = 0;

    void makeDrink(){
        Boil();
        Brew();
        PourInCup();
        PutSomething();
    }
};

class Coffee: AbstractDrinking{
    void Boil(){
        cout<<"煮水"<<endl;
    }
    void Brew(){
        cout<<"沖泡咖啡"<<endl;
    }
    void PourInCup(){
        cout<<"倒入杯中"<<endl;
    }
    void PutSomething(){
        cout<<"加糖"<<endl;
    }
};

class Tea: AbstractDrinking{
    void Boil(){
        cout<<"煮開水"<<endl;
    }
    void Brew(){
        cout<<"沖泡茶葉"<<endl;
    }
    void PourInCup(){
        cout<<"倒入杯中"<<endl;
    }
    void PutSomething(){
        cout<<"加枸杞"<<endl;
    }
};

void doWork(AbstractDrinking* abs){
    abs->makeDrink();
    delete abs;
}

void test01(){
    doWork(new Coffee);
    cout<<"-----------"<<endl;
    doWork(new Tea);
}
           

4.7.5 虛析構和純虛析構

多态使用時,子類屬性開辟到堆區時,父類指針在釋放時(delete)不調用子類的析構函數。

Animal::~Animal() {
    ...
}
           

4.7.6 多态案例3-電腦組裝

#include<iostream>
#include<string>

using namespace std;


class  CPU
{
public:
	virtual void calculate() = 0;
};

class  VideoCard
{
public:
	virtual void display() = 0;
};

class  Memory
{
public:
	virtual void store() = 0;
};

class Computer 
{
public:
	Computer(CPU * t_cpu, VideoCard * t_vc, Memory * t_mem ) {
		cpu = t_cpu;
		vc = t_vc;
		memory = t_mem;
	}
	~Computer() {
		if (cpu != NULL) {
			delete cpu;
			cpu = NULL;
		}
		if (vc != NULL) {
			delete vc;
			vc = NULL;
		}
		if (memory != NULL) {
			delete memory;
			memory = NULL;
		}
	}
	void work() {
		cpu->calculate();
		vc->display();
		memory->store();
	}

private:
	CPU * cpu;
	VideoCard * vc;
	Memory * memory;
};

//具體廠商
class IntelCPU : public CPU 
{
public:
	virtual void calculate() {
		cout << "Intel 的CPU工作中..." << endl;
	}
};

class IntelVideoCard : public VideoCard
{
public:
	virtual void display() {
		cout << "Intel 的顯示卡工作中..." << endl;
	}	
};
class IntelMemory : public Memory
{
public:
	virtual void store() {
		cout << "Intel 的記憶體工作中..." << endl;
	}
};

class NvidiaVideoCard : public VideoCard
{
public:
	virtual void display() {
		cout << "Nvidia 的顯示卡工作中..." << endl;
	}
};
void test01()
{
	Computer * cp1 = new Computer(new IntelCPU,
								  new IntelVideoCard,new IntelMemory);
	cp1->work();
	delete cp1;

	cout << endl; 
	Computer * cp2 = new Computer(new IntelCPU,
		new NvidiaVideoCard, new IntelMemory);
	cp2->work();
	delete cp2;
}
int main() {
	test01();
	return 0;
}
           

繼續閱讀