## 今天学了什么
今天学习C++的多态。
## 多态的分类
静态多态:函数重载、运算符重载、模板,复用函数名;
动态多态:派生类和虚函数实现运行时。
*注:静态多态和静态函数/静态变量(static)没有关系,只是相对于动态多态的叫法。
①静态多态和动态多态的区别:
- 静态多态的函数地址早绑定:编译阶段 确定函数地址;
- 动态多态的函数地址晚绑定:运行阶段 确定函数地址;
②动态多态的满足条件:
- 有继承关系;
- 子类要重写父类的虚函数;
③动态函数的使用:父类的指针或者引用要指向子类对象;
④多态的优点:
- 代码组织结构清晰,可读性强;
- 利于前期和后期的扩展和维护;
## 纯虚函数和抽象类
纯虚函数:在多态中,通常父类虚函数用处不大,主要都是子类调用重写,由此可以改为纯虚函数。
语法:virtual 返回值类型 函数名(参数列表)=0;
抽象类:当类中有纯虚函数,这个类也称为抽象类。
抽象类的特点:
- ①无法实例化对象;
- ②子类必须重写抽象类中的纯虚函数,否则也属于抽象类。
## 虚析构和纯虚析构
虚析构语法:
virtual ~ 类名(){}
纯虚析构语法:
class Base{
…
virtual ~ 类名(){}=0;
}
…
类名::~类名(){ …}
问题:在多态使用时,子类中有属性开辟到堆区,父类指针在释放时无法调用子类的析构函数,造成内存泄漏;
解决方法:将父类的析构改为虚析构/纯虚析构;
验证:
class Animal {
public:
Animal()
{
cout << "Animal 构造函数" << endl;
}
virtual void speak() = 0;
~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 test()
{
Animal* an = new Cat("Tom");
an->speak();
delete an;
}
运行发现,打印结果没有cat的析构函数,在speak()处下断点,进入调试,发现在执行完speak函数以后,直接进入了Animal的析构函数,并没有进入Cat的析构函数,所以导致cat类的m_name指针无法释放。将父类的析构改为虚析构,重复调试步骤,发现这一次进入了cat的析构函数,验证成功。
虚析构和纯虚析构的共性:
- 可以解决父类指针释放子类对象;
- 都需要有具体的函数实现;
区别:纯虚析构的类属于抽象类,无法实例化对象。
*注:如果子类中没有堆区数据可以不写虚析构/纯虚析构。
## 练习
1.利用多态实现计算器:
#include<iostream>
using namespace std;
class calculator {
public:
virtual int getResult()
{
return 0;
}
int num1;
int num2;
};
class Addcalculator:public calculator {
public:
int getResult()
{
return num1 + num2;
}
};
class Subcalculator :public calculator {
public:
int getResult()
{
return num1 – num2;
}
};
class Mulcalculator :public calculator {
public:
int getResult()
{
return num1 * num2;
}
};
void test()
{
calculator* cal = new Addcalculator;
cal->num1 = 10;
cal->num2 = 10;
cal->getResult();
cout << cal->num1 << " + " << cal->num2 << " = " << cal->getResult() << endl;
delete cal;
cal = new Subcalculator;
cal->num1 = 10;
cal->num2 = 10;
cout << cal->num1 << " – " << cal->num2 << " = " << cal->getResult() << endl;
delete cal;
cal = new Mulcalculator;
cal->num1 = 10;
cal->num2 = 10;
cout << cal->num1 << " * " << cal->num2 << " = " << cal->getResult() << endl;
delete cal;
}
int main()
{
test();
return 0;
}
## 补充
虚函数调用链:
Animal *p=new Dog();
p->speak();
顺序:
1.p是父类指针,指向Dog类的对象;
2.Dog对象内部有_vfptr(virtual function pointer,虚函数指针);
3._vfptr指向Dog类的虚函数表;
4.虚函数表中[0]是Dog::speak;
5.最终执行Dog::speak。
网硕互联帮助中心




评论前必须登录!
注册