首先需要明确多态性的用途,是为了接口的最大程度复用,以及其定义:
多态性的定义,可以简单地概括为“一个接口,多种方法”,程序在运行时才决定调用的函数,它是面向对象编程领域的核心概念。多态(polymorphism),字面意思多种形状。多态分为静态多态和动态多态。
静态多态是通过重载和模板技术实现,在编译的时候确定。
动态多态通过虚函数和继承关系来实现,执行动态绑定,在运行的时候确定。
定义明确,接下来看看最常见的动态多态的实现思路:对于一组相关的数据类型,抽象出它们之间共同的功能集合,在基类中将共同的功能声明为多个公共虚函数接口,子类通过重写这些虚函数,实现各自对应的功能。在调用时,通过基类的指针来操作这些子类对象,所需执行的虚函数会自动绑定到对应的子类对象上。
上述可以看出,动态多态的实现关键在于虚函数,基类通过virtual关键字声明和实现虚函数,此时基类会拥有一张虚函数表,虚函数表会记录其对应的函数指针。当子类继承基类时,子类也会获得一张虚函数表,不同之处在于,子类如果重写了某个虚函数,其在虚函数表上的函数指针会被替换为子类的虚函数指针。
1.实现代码#include2.虚析构和纯虚析构using namespace std; // 动物类 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() { Animal animal; doSpeak(animal); Cat cat; doSpeak(cat); Dog dog; doSpeak(dog); } //分别利用普通写法和多态技术实现计算器 //普通写法 class Calculator { public: int retResult(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 { return m_num1 / m_num2; } //如果想扩展新的功能,需求修改源码 //在真是开发中提倡开闭原则 //开闭原则:对扩展进行开发2,对修改代码进行关闭 } int m_num1; int m_num2; }; void test02() { //创建计算器操作数 Calculator c; c.m_num1 = 10; c.m_num2 = 10; cout << c.retResult("+"); } //利用多态实现计算器 class AbstractCalculator { public: virtual int getResult() { return 0; } int m_num1; int m_num2; }; //加法计算器 class AddCalulator:public AbstractCalculator { public: int getResult() { return m_num1 + m_num2; } }; //加法计算器 class SubCalulator :public AbstractCalculator { public: int getResult() { return m_num1 - m_num2; } }; //乘法计算器 //加法计算器 class MultCalulator :public AbstractCalculator { public: int getResult() { return m_num1 * m_num2; } }; void test03() { //多态的使用条件 //父类指针或者引用指向子类对象 //加法运算 AbstractCalculator* abc = new AddCalulator; abc->m_num1 = 10; abc->m_num2 = 10; cout << abc->m_num1 << "+" << abc->m_num2 << " = " << abc->getResult() << endl; delete abc; } int main() { test01(); test03(); }
虚析构函数和纯虚析构函数区别在哪里?作为两点介绍:
1、虚析构函数:
主要作用是为了来解决基类指针指向派生类对象,并用基类指针释放派生类对象。也就是说父类的虚析构函数,会调用派生类的析构函数。有虚析构函数的类是抽象类,不能实例化对象,不需要在类外实现;
2、纯虚析构函数:
有纯虚析构函数的类它是抽象类,不能实例化对象,而且要在类外实现;
#include#include 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(string name) { cout << "cat 构造函数调用"< speak(); //父类指针在析构函数,不会调用子类中的析构函数,导致子类如果有堆区属性,出现内存泄漏。 delete animal; } int main() { test01(); }



