持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第16天,点击查看活动详情
1、纯虚函数
C++中我们可以通过虚函数来时实现多态,但是在父类中虚函数的实现是毫无意义的,重要都是调用子类中的重写的内容,所以我们可以把父类中的虚函数给位纯虚函数,方法如下:
virtual 返回值类型 函数名(参数列表)= 0;
当父类中与纯虚函数我们就称该类为抽象类,抽象类是不能实例化对象的,而其子类中也要重写父类中的纯虚函数否则也是抽象类。
2、虚析构
先写一个Animal的父类,不使用虚析构
class Animal{
public:
virtual void speak() = 0;//使用虚构函数实现多态
Animal(){
cout << "Animal的构造函数调用!" << endl;
}
/*virtual*/ ~Animal(){//这里把“virtual”给注释掉了。
//解决方法,利用虚析构可以解决父类指针释放子类对象时释放不干净的问题。
cout << "Animal的析构函数调用!" << endl;
}
};
再写一个Cat的子类继承Animal
class Cat :public Animal{
public:
void speak(){
cout <<*m_Name<< "小猫喵喵叫!" << endl;
}
Cat(string name)//构造函数{
cout << "Cat的构造函数调用!" << endl;
m_Name = new string(name);//堆区创建的属性,要提供对应的析构函数
}
~Cat(){
if (m_Name != NULL){
cout << "Cat的析构函数调用!" << endl;
delete m_Name;
}
}
string *m_Name;
};
此时我们创建一个Cat的对象,观察构造函数和析构函数的调用
void test01(){
Animal *cat = new Cat("mimi");
//使用Animal在堆区开辟空间,使用Cat的个构造函数初始化。
cat->speak();
delete(cat);
}
如下图,此时会调用Animal和Cat的构造函数,但只调用Animal的析构函数。就会造成了堆区的内容没有释放干净。
如何解决这个问题,仅需一个小小的改动,那就是在Animal的析构函数前加上 virtual ,使其变成虚析构再次运行会得到:
会发现即调用了Animal和Cat的构造函数,又调用了Animal和Cat的析构函数,堆区的内容被释放干净了。
3、纯虚析构
我们可以把普通的虚析构改为纯虚析构
virtual ~Animal() = 0;//纯虚析构,仅为声明
需要注意的是在类中写纯虚析构仅为声明,我们需要在类外重新声明一下:
Animal::~Animal() { cout << "Animal纯虚析构调用!" << endl; }//纯虚析构,具体实现,作用域不要忘记
4、总结
使用虚函数实现多态过程中,当我们需要在堆区开辟空间的时候,那么在程序结束之前,这片内存空间需要程序员自己释放干净。编译器会先调用父类的构造函数再调用子类的构造函数,而只调用父类的构造不会调用子类的构造函数。这个问题可以把父类的析构函数改为虚析构来解决,也可用纯虚析构的方法。