多态存在的意义:增加代码的可扩展性
多态的实现方式:当父类的指针或引用指向子类地址或对象时, 发生多态
触发前提:
1.子类继承自父类
2.父类中有虚函数(virtual), 且子类中重写了父类的虚函数(子类的函数前的“virtua”可加可不加)
多态的白话理解:父类中提供原料与模板(饭店前台),子类对其进行加工(饭店后厨)。当有顾客来时,通过父类(记下顾客点的菜名)间接调用子类中重写的虚函数(去后厨找儿子),完成每个子类的相应功能
- 多态naive实现
class calculator
{
public:
virtual int add() {
cout << " 开业大酬宾!!(do nothing) " << endl;
}
int a;
int b;
};
class Plus : public calculator
{
public:
int add() {
cout << "家人们用我爹给我的猪肉(a)和大鹅(b)炖了两道菜:猪肉炒大葱+铁锅炖大鹅!" << endl;
return a + b;
}
};
int main()
{
// 发生多态的条件
// 1. 继承关系
// 2. 子类中重写父类的虚函数
// 3. 父类的指针或引用指向子类对象
// 方式1:父类引用指向子类对象
// Plus base;
// calculator& p = base;
// p.a...
// 方式2:父类指针指向子类地址
Plus* base = new Plus;
calculator* p = base;
p->a = 2;
p->b = 5;
cout << p->add() << endl;
delete(p);
return 0;
}
1. 多态中的其他概念:纯虚函数、抽象类
父类中的虚函数内部实现往往没啥意义,干脆全都去掉,改写为:
class calculator
{
public:
virtual int add() = 0;
...
这样一来简洁了不少,但这样会将虚函数变为纯虚函数,关于纯虚函数有如下特点:
1. 包含纯虚函数的类称为抽象类,且抽象类无法实例化对象!
2. 抽象类的子类如果不重写父类中的纯虚函数,则子类也将称为抽象类(中毒过深)
2. 多态中的其他概念:虚析构、纯虚析构
如果子类有属性开辟到堆区,肯定要在自身的析构代码中delete掉,像这样:
class Plus : public calculator
{
public:
Plus() {
s = new string("abc");
}
int add() {
return a + b;
}
~Plus() {
cout << "子类析构" << endl;
delete(s);
}
string* s;
};
但在多态以“父类指针指向子类地址”触发的前提下(父类引用指向子类对象没有这种问题!),程序结束时只会调用父类的析构,子类的析构无法执行到,应该是因为new的时候没真正创建一个对象,所以子类析构没机会执行。
这时候需要将父类的析构函数变为虚析构或者纯虚析构,才能执行到子类的析构代码。实现方式如下:
class calculator
{
public:
virtual int add() = 0;
int a;
int b;
virtual ~calculator() {}; // 虚析构就加个virtual
};
class calculator
{
public:
virtual int add() = 0;
int a;
int b;
virtual ~calculator() = 0; // 纯虚析构需要类外实现
};
calculator::~calculator() {
}
至于两者应该没啥区别,另外包含纯虚析构的类也属于抽象类注意下