多态
1 多态的基本概念
多态是C++面向对象三大特性之一
多态分为两类
- 静态多态: 函数重载 和 运算符重载属于静态多态,复用函数名
- 动态多态: 派生类和虚函数实现运行时多态
多态满足条件:
多态使用:父类指针或引用指向子类对象
静态多态和动态多态区别:
- 静态多态的函数地址早绑定 - 编译阶段确定函数地址
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| class Animal{ public: void speak(){ cout<<"动物在说话"<<endl; } }; class Cat:public Animal{ public: void speak(){ cout<<"小猫在说话"<<endl; } };
void dospeak(Animal &animal){ animal.speak(); } void test01(){ Cat cat; dospeak(cat); }
|
运行结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class Animal{ public: virtual void speak(){ cout<<"动物在说话"<<endl; } }; class Cat:public Animal{ public: void speak(){ cout<<"小猫在说话"<<endl; } };
|
运行结果:
2 纯虚函数和抽象类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| class Animal{ public: virtual void speak() = 0; }; class Cat:public Animal{ public: void speak(){ cout<<"小猫在说话"<<endl; } }; void dospeak(Animal &animal){ animal.speak(); } void test01(){ Animal *base = NULL; base = new Cat; base->speak(); delete base; }
|
3 虚析构和纯虚析构
多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码。
解决方式:将父类中的析构函数改为虚析构或者纯虚析构
虚析构和纯虚析构共性:
- 可以解决父类指针释放子类对象
- 都需要有具体的函数实现
虚析构和纯虚析构区别:如果是纯虚析构,该类属于抽象类,无法实例化对象
虚析构语法:virtual ~类名(){}
纯虚析构语法:
virtual ~类名() = 0;
类名::~类名(){}
**示例:下面这个例子,父类指针析构时不会调用子类的析构函数,导致如果子类有数据在堆区但是释放不了,内存泄漏 **
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| class Animal{ public: virtual void speak() = 0; Animal(){ cout<<"Animal的构造函数"<<endl; } ~Animal(){ cout<<"Animal的析构函数"<<endl; } }; class Cat:public Animal{ public: 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 dospeak(Animal &animal){ animal.speak(); } void test01(){ Animal *base = new Cat("Tom"); base->speak(); delete base; }
|
运行结果:
1 2 3 4
| Animal的构造函数 Cat的构造函数 Tom小猫在说话 Animal的析构函数
|
将父类的析构函数修改为虚函数后
1 2 3
| virtual ~Animal(){ cout<<"Animal的析构函数"<<endl; }
|
运行结果:
1 2 3 4 5
| Animal的构造函数 Cat的构造函数 Tom小猫在说话 Cat的析构函数 Animal的析构函数
|
将父类的析构函数修改为纯虚析构后,必须要在类外实现,防止父类有堆区数据
1 2 3 4 5 6 7 8 9 10 11
| class Animal{ public: virtual void speak() = 0; Animal(){ cout<<"Animal的构造函数"<<endl; } virtual ~Animal() = 0; }; Animal::~Animal(){ cout<<"Animal的纯虚析构"<<endl; }
|