C++的析构函数为什么要定义为虚函数

首先说明,不一定要定义为虚函数!

只有当这个类要给别人作为基类时,才要定义为虚函数,原因是:

当使用多态指针时,基类释放后,不会释放派生类资源,造成内存泄漏!看下面第二题。

看题:

第一题:各顾各的

//基类
 class A{   
 public :
       A(){ cout<<"A构造函数"<<endl; }
       ~A(){cout<<"A被销毁了"<<endl;}
       void Do(){
           cout<<"A要做点什么"<<endl;
       }
};
//派生类
 class B :public A{    
 public :
        B(){ cout<<"B构造函数"<<endl;}
        ~B(){ cout<<"B被销毁了"<<endl;}
        void Do(){ cout<<"B要做点什么"<<endl;}
};
// 派生类 指针=new 派生类
int main(){
    B *p=new B;
    p->Do();
    delete p;
    return 0;
}


B  *p = new B;      那么就会执行基类构造函数A(),派生类构造函数B()
p->Do();   通过派生类指针可以调用派生类的成员函数 B->Do()
delete p;  先调用派生类析构函数~B(),在调用基类构造函数~A()

这个例子完美,纯粹派生类操作,不存在多态概念。


第二题:引入多态

#include<iostream>
using namespace std;
//基类、派生类不变

// 基类 指针 = new 派生类 (派生类指针转化成基类指针),引入多态性
int main(){
    A *p= new B;
    p->Do();
    delete p;
    return 0;
}


A *p = new B;  依旧要先调用基类构造函数A(),再派生类构造函数B()
p ->Do();    通过基类指针调用基类成员函数A->Do(),此处只能调用基类里面有的成员函数A->Do(),当调用派生类中成员函数会提示基类中并没有这个成员
delete p;      这里只会调用基类的析构函数~A(),所以内存释放并不完全(~B()不会被调用)


第三题:引入虚析构函数

//基类
class A{   
public :
    A(){ cout<<"A构造函数"<<endl; }
    virtual ~A(){cout<<"A被销毁了"<<endl;}
    void Do(){
        cout<<"A要做点什么"<<endl;
    }
};

再次执行:

#include<iostream>
using namespace std;
//基类、派生类不变

// 基类 指针 = new 派生类 (派生类指针转化成基类指针)
int main(){
    A *p= new B;
    p->Do();
    delete p;
    return 0;
}

然后 delete p; 就会释放派生类~B(),释放基类~A(). 内存全部释放了。


总结:

引入虚函数后,因为基类对象的指针可以指向派生类的对象(多态性),所以如果删除指针delete p,那么就会调用派生类得析构函数,但是派生类的析构函数就会调用基类的析构函数,这样整个派生类的对象完全被释放。但是如果不被声明成虚函数,那么删除指针时,只会调用基类的析构函数,而不会调用派生类的析构函数,这样释放对象就只释放不完全,所以把析构函数定义成虚函数是十分必要的。


还有派生类指针转换成基类指针的时候,调用同名成员函数Do()的时候,一定要调用基类的成员函数Do(),因为此时基类的成员函数覆盖了派生类的同名成员函数。这时也需要引入虚函数来实现多态,就可以调用派生类的成员函数了。


文章部分来自:https://blog.csdn.net/ananpanke72830/article/details/102335195


本文为3YL原创,转载无需联系,但请注明来自labisart.com。

原创文章不易,如果觉得有帮助,可打赏或点击右侧广告支持:

查看打赏记录

发表评论请遵守党国法律!后台审核后方可显示!
  • 最新评论
  • 总共0条评论
  • Blog v1.1© 2024 labisart.com 版权所有 | 联系:labartwork@163.com