目录
一,多态的基本介绍
1.多态的基本语法
2.多态满足条件
3.多态使用条件
4.多态的优点
二,纯虚函数和抽象类
三,虚析构和纯虚析构
四,多态案例
class animal
class calculator
make drinking
assembly computer
一,多态的基本介绍
1.多态的基本语法
重写:virtual 函数值返回类型 函数名 参数列表2.多态满足条件
有继承关系子类重写父类中的虚函数3.多态使用条件
父类指针或引用指向子类对象4.多态的优点
代码组织结构清晰可读性强利于前期和后期的扩展以及维护二,纯虚函数和抽象类
在多态中,通常父类中的虚函数的实现是没有意义的,主要是调用子类重写的内容,因此可以将虚函数改为纯虚函数。
纯虚函数的语法: virtual 返回值类型 函数名 (形参列表) = 0;
当类中有了纯虚函数,这个类也称为抽象类。
抽象类的特点
无法实例化对象子类必须重写抽象类中的纯虚函数,否则也属于抽象类For example
#include <iostream>using namespace std;// 纯虚函数和抽象类class Base{public: // 纯虚函数 // 只要有一个纯虚函数,这个类称为抽象类 // 抽象类的特点: // 1.无法实例化对象 // 2.抽象类的子类 必须重写父类中的纯虚函数,否则也属于抽象类 virtual void func() = 0;};class Son :public Base{public: virtual void func() { cout << "output the son result" << endl; }};void test01(){ // Base b; // 抽象类无法实例化对象 // new Base; // 抽象类无法实例化对象 Son s; // 子类必须重写父类中的纯虚函数,否则无法实现实例化对象。 Base * base = new Son; base->func();}int main(){ test01(); return 0;}
Result:
三,虚析构和纯虚析构
多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放的时候无法调用到子类的析构代码。
解决方式:将父类中的析构函数改为虚析构或者纯虚析构。
虚析构和纯虚析构的共性:
可以解决父类指针释放子类对象都需要有具体的函数实现纯虚析构和虚析构的区别:
如果是是纯虚析构函数,该类属于抽象类,无法实例化对象。
虚析构语法:
virtual ~类名()
{
...
}
纯虚析构的语法:
virtual ~类名() = 0;
类名::类名()
{
...
}
For example:(调用虚析构函数)
#include <iostream>#include <string>using namespace std;// 虚析构和纯虚析构class Animal{public: Animal() { cout << "Animal的构造函数调用" << endl; } // 利用虚析构函数可以解决父类指针释放子类对象时不干净的问题 virtual ~Animal() { cout << "Animal的虚析构函数调用" << endl; } // 纯虚析构 需要声明 需要实现 //virtual ~Animal() = 0; // 纯虚函数 virtual void speak() = 0;};/*Animal::~Animal(){ cout << "Animal的纯虚析构函数调用" << endl;}*/class Cat :public Animal{public: Cat(string name) { cout << "Cat的构造函数调用" << endl; m_Name = new string (name); } virtual 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 * animal = new Cat("Tom"); animal->speak(); // 父类指针在析构的时候 不会调用子类中的析构函数,导致子类如果有堆区属性,出现内存泄露 delete animal;}int main(){ test01(); return 0;}
Result:
For example:(调用纯虚析构函数)
#include <iostream>#include <string>using namespace std;// 虚析构和纯虚析构class Animal{public: Animal() { cout << "Animal的构造函数调用" << endl; } // 利用虚析构函数可以解决父类指针释放子类对象时不干净的问题 /*virtual ~Animal() { cout << "Animal的虚析构函数调用" << endl; }*/ // 纯虚析构 需要声明 需要实现 virtual ~Animal() = 0; // 纯虚函数 virtual void speak() = 0;};Animal::~Animal(){ cout << "Animal的纯虚析构函数调用" << endl;}class Cat :public Animal{public: Cat(string name) { cout << "Cat的构造函数调用" << endl; m_Name = new string (name); } virtual 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 * animal = new Cat("Tom"); animal->speak(); // 父类指针在析构的时候 不会调用子类中的析构函数,导致子类如果有堆区属性,出现内存泄露 delete animal;}int main(){ test01(); return 0;}
Result:
All in all:
虚析构和纯虚析构就是用来解决通过父类指针释放子类对象如果子类中没有堆区属性,可以不写虚析构和纯虚析构拥有纯虚析构函数的类也属于抽象类四,多态案例
class animal
#include <iostream>using namespace std;// 多态// 动物类class Animal{public: // 虚函数 virtual void speak() { cout << "动物在说话" << endl; }};// 猫类class Cat :public Animal{public: // 重写 函数返回值类型 函数名 参数列表 完全相同 virtual void speak() { cout << "小猫在说话" << endl; }};// 狗类class Dog :public Animal{public: // 重写 函数返回值类型 函数名 参数列表 完全相同 virtual void speak() { cout << "小狗在说话" << endl; }};// 执行说话的函数// 地址早已绑定 在编译阶段确定函数地址// 如果想执行让猫说话,那么这个函数不能提前绑定,要在运行阶段进行绑定,地址晚绑定void doSpeak(Animal &animal) // Animal & animal == cat;{ animal.speak();}void test01(){ Cat cat; doSpeak(cat); Dog dog; doSpeak(dog);}int main(){ test01(); return 0;}
Result:
class calculator
#include <iostream>#include <string>using namespace std;// 分别利用基本写法和多态技术实现计算器// 普通写法class Calculator{public: int getResult(string oper) { if(oper == "+") { return m_Num1 + m_Num2; } else if(oper == "-") { return m_Num1 - m_Num2; } else if(oper == "*") { return m_Num1 * m_Num2; } else if(oper == "/") { return m_Num1 / m_Num2; } } int m_Num1; int m_Num2; // 如果想拓展新的功能,需要修改源码 // 在真实开发中提倡开闭原则 // 开闭原则:对扩展进行开发,对修改进行关闭};void test01(){ // 创建计算器对象 Calculator c; c.m_Num1 = 10; c.m_Num2 = 10; cout << c.m_Num1 << " + " << c.m_Num2 << " = " << c.getResult("+") << endl; cout << c.m_Num1 << " - " << c.m_Num2 << " = " << c.getResult("-") << endl; cout << c.m_Num1 << " * " << c.m_Num2 << " = " << c.getResult("*") << endl; cout << c.m_Num1 << " / " << c.m_Num2 << " = " << c.getResult("/") << endl;}// 利用多态实现计算器// 实现计算器抽象类class AbstractCalculator{public: virtual int getResult() { return 0; } int m_Num1; int m_Num2;};// 加法计算器类class Add :public AbstractCalculator{ virtual int getResult() { return m_Num1 + m_Num2; }};// 减法计算器类class Sub :public AbstractCalculator{ virtual int getResult() { return m_Num1 - m_Num2; }};// 乘法计算器类class Mul :public AbstractCalculator{ virtual int getResult() { return m_Num1 * m_Num2; }};// 除法计算器类class Div :public AbstractCalculator{ virtual int getResult() { return m_Num1 / m_Num2; }};void test02(){ // 多态使用条件 // 父类指针或者引用指向子类对象 // 加法运算 AbstractCalculator * abc = new Add; abc->m_Num1 = 20; abc->m_Num2 = 20; cout << abc->m_Num1 << " + " << abc->m_Num2 << " = " << abc->getResult() << endl; delete abc; // 减法运算 abc = new Sub; abc->m_Num1 = 20; abc->m_Num2 = 20; cout << abc->m_Num1 << " - " << abc->m_Num2 << " = " << abc->getResult() << endl; delete abc; // 乘法运算 abc = new Mul; abc->m_Num1 = 20; abc->m_Num2 = 20; cout << abc->m_Num1 << " * " << abc->m_Num2 << " = " << abc->getResult() << endl; delete abc; // 除法运算 abc = new Div; abc->m_Num1 = 20; abc->m_Num2 = 20; cout << abc->m_Num1 << " / " << abc->m_Num2 << " = " << abc->getResult() << endl; delete abc;}int main(){ cout << "test01" << endl; test01(); cout << endl; cout << "test02" << endl; test02(); return 0;}
Result:
make drinking
#include <iostream>using namespace std;// make drinkingclass BaseDrinking{public: virtual ~BaseDrinking() { // 基类析构函数实现 } // 煮水 virtual void Boil() = 0; // 冲泡 virtual void Brew() = 0; // 倒入杯中 virtual void PourInCup() = 0; // 加入辅料 virtual void AddSomethings() = 0; // 制作饮品 void MakeDrink() { Boil(); Brew(); PourInCup(); AddSomethings(); }};// 制作咖啡class Coffee :public BaseDrinking{public: // 煮水 virtual void Boil() { cout << "煮农夫山泉" << endl; } // 冲泡 virtual void Brew() { cout << "冲泡咖啡" << endl; } // 倒入杯中 virtual void PourInCup() { cout << "倒入咖啡杯中" << endl; } // 加入辅料 virtual void AddSomethings() { cout << "加入糖和牛奶" << endl; }};// 制作茶class Tea :public BaseDrinking{public: // 煮水 virtual void Boil() { cout << "煮娃哈哈" << endl; } // 冲泡 virtual void Brew() { cout << "冲泡茶" << endl; } // 倒入杯中 virtual void PourInCup() { cout << "倒入茶杯中" << endl; } // 加入辅料 virtual void AddSomethings() { cout << "加入柠檬" << endl; }};// 制作函数void doWork(BaseDrinking * base){ base->MakeDrink(); delete base; // 释放}void test01(){ // 制作咖啡 doWork(new Coffee); cout << "---------------------" << endl; // 制作茶 doWork(new Tea);}int main(){ test01(); return 0;}
Result:
assembly computer
#include <iostream>using namespace std;// 组装电脑// 抽象不同的零件类// 抽象CPU类class CPU{public: virtual ~CPU() { } // 抽象的计算函数 virtual void calculate() = 0;};// 抽象显卡类class VideoCard{public: virtual ~VideoCard() { } // 抽象的显示函数 virtual void display() = 0;};// 抽象内存条类class Memory{public: virtual ~Memory() { } // 抽象的存储函数 virtual void storage() = 0;};class Computer{public: Computer(CPU * cpu, VideoCard * vc, Memory *mem) { m_cpu = cpu; m_vc = vc; m_mem = mem; } // 提供工作的函数 void work() { // 让零件工作起来,调用接口 m_cpu->calculate(); m_vc->display(); m_mem->storage(); } // 提供析构函数 释放3个电脑零件 virtual ~Computer() { // 释放CPU零件 if (m_cpu != NULL) { delete m_cpu; m_cpu = NULL; } // 释放显卡零件 if (m_vc != NULL) { delete m_vc; m_vc = NULL; } // 释放内存条零件 if (m_mem != NULL) { delete m_mem; m_mem = NULL; } }private: CPU * m_cpu; // CPU的零件指针 VideoCard * m_vc; // 显卡零件指针 Memory * m_mem; // 内存条零件指针};// 具体厂商// intel厂商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 storage() { cout << "Intel的内存条开始存储了" << endl; }};// AMD厂商class AMDCPU :public CPU{public: virtual void calculate() { cout << "AMD的CPU开始计算了" << endl; }};class AMDVideoCard :public VideoCard{public: virtual void display() { cout << "AMD的显卡开始显示了" << endl; }};class AMDMemory :public Memory{public: virtual void storage() { cout << "AMD的内存条开始存储了" << endl; }};void test01(){ // 第一台电脑零件 CPU * intelcpu = new IntelCPU; VideoCard * intelCard = new IntelVideoCard; Memory * intelMem = new IntelMemory; cout << "第一台电脑开始工作:" << endl; // 创建第一台电脑 Computer * Computer1 = new Computer(intelcpu, intelCard, intelMem); Computer1->work(); delete Computer1; cout << "----------------------" << endl; cout << "第二台电脑开始工作:" << endl; // 第二台电脑组装 Computer * Computer2 = new Computer(new AMDCPU, new AMDVideoCard, new AMDMemory); Computer2->work(); delete Computer2;}int main(){ test01(); return 0;}
Result: