C++: 析构函数为什么要为虚函数

27 篇文章 2 订阅

  基类指针或引用可以指向或是引用派生类对象,下文以指针为例作讲解。引用的例子类似,不再赘述。
  如果基类指针向派生类对象,则删除此指针时,我们希望调用该指针指向的派生类析构函数,而派生类的析构函数又自动调用基类的析构函数,这样整个派生类的对象完全被释放。
  若使用基类指针操作派生类,需要防止在析构时,只析构基类,而不析构派生类。
  但是,如果析构函数不被声明成虚函数,则编译器采用的绑定方式是静态绑定,在删除基类指针时,只会调用基类析构函数,而不调用派生类析构函数,这样就会导致基类指针指向的派生类对象析构不完全。若是将析构函数声明为虚函数,则可以解决此问题。
比较以下三个例子:
1、第一段代码

#include<iostream>
using namespace std;
class BC{
public:
    BC () { strsBC = new string[10]; cout << "BC::BC()!" << endl;};
    ~BC() {delete [] strsBC; cout << "free strsBC in BC::~BC()!" << endl;};
void fun1() { cout << "BC::fun1()!" << endl; };
private:
    string * strsBC;
};

class DC : public BC{
public:
    DC () {pa = new int[6]; cout << "DC::DC()!" << endl; };
    ~DC () {delete [] pa; cout << "free pa in DC::~DC()!" << endl; };
    void fun1() { cout << "DC::fun1()!" << endl; };
private:
    int *pa;
};
int main(){  
  DC *p =  new DC();
  p->fun1();
  delete p;
  return 0;
}

运行结果:
BC::BC()!
DC::DC()!
DC::fun1()!
free pa in DC::~DC()!
free strsBC in BC::~BC()!
  这段代码中,基类析构函数不是虚函数。在main函数中,用子类指针操作子类。释放指针P的过程是:先释放继承类的资源,再释放基类资源,则释放是完全的,不存在问题。

2、第二段代码

#include<iostream>
using namespace std;
class BC{
public:
    BC () { strsBC =new string[10]; cout << "BC::BC()!" << endl;};
    ~BC() {delete [] strsBC; cout << "free strsBC in BC::~BC()!" << endl;};
void fun1() { cout << "BC::fun1()!" << endl; };
private:
    string * strsBC;
};

class DC : public BC{
public:
    DC () {pa = new int[6]; cout << "DC::DC()!" << endl; };
    ~DC () {delete [] pa; cout << "free pa in DC::~DC()!" << endl; };
    void fun1() { cout << "DC::fun1()!" << endl; };
private:
    int *pa;
};
int main(){  
  BC *p =  new DC;
  p->fun1();
  delete p;
  return 0;
}

输出结果:
BC::BC()!
DC::DC()!
BC::fun1()!
free strsBC in BC::~BC()!
  这段代码中,基类析构函数不是虚函数,但在main函数中,用基类指针操作子类,释放指针P的过程是:只是释放了基类申请的资源,而没有调用子类的析构函数,没有释放了子类申请的资源。调用fun1()函数,执行的也是基类定义的函数。
  一般情况下,这样的删除只能够删除基类对象,而不能删除子类对象,形成了删除一半形象,造成内存泄漏。
  要想解决上述问题,需要声明析构函数是虚函数。

3、第三段代码:

#include<iostream>
using namespace std;
class BC{
public:
    BC () { strsBC =new string[10]; cout << "BC::BC()!" << endl;};
    virtual ~BC() {delete [] strsBC; cout << "free strsBC in BC::~BC()!" << endl;};
virtual void fun1() { cout << "BC::fun1()!" << endl; };
private:
    string * strsBC;
};

class DC : public BC{
public:
    DC () {pa = new int[6]; cout << "DC::DC()!" << endl; };
    ~DC () {delete [] pa; cout << "free pa in DC::~DC()!" << endl; };
    void fun1() { cout << "DC::fun1()!" << endl; };
private:
    int *pa;
};
int main(){  
  BC *p =  new DC;
  p->fun1();
  delete p;
  return 0;
}

运行结果:
BC::BC()!
DC::DC()!
DC::fun1()!
free pa in DC::~DC()!
free strsBC in BC::~BC()!

  这段代码中,基类析构函数是虚函数。在main函数中,用基类指针操作子类,释放指针P的过程是:先释放子类申请的资源,再调用基类析构函数,释放父类申请的资源。调用fun1()函数,执行的也是子类中定的函数,表现出了多态特征。

  • 15
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值