0
点赞
收藏
分享

微信扫一扫

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)不调用子类的析构函数。

解决方法:父类中使用虚析构或纯虚析构。 virtual ~Animal(){}virtual ~Animal() = 0;

注意这个纯虚函数也是要有实现的(回收父类中创建的内存空间)

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

4.7.6 多态案例3-电脑组装

抽象实现电脑的3个主要组件(CPU、显卡、内存条),然后实现具体的生产厂家。 再实现一个电脑类,包含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;
}
举报

相关推荐

0 条评论