虚析构函数

原创 2018年04月15日 11:40:39

需要虚析构函数的原因:

首先看一下这段代码:

#include <iostream>
using namespace std;

class A {
private: 
    int *a;
public: 
    A() { a = new int; cout << "A::A() is called.\n"; }
    ~A() { delete a; cout << "A::~A() is called.\n"; }
    void print() { cout << "A::print() is called.\n"; }
};

class B : public A {
private: 
    int *b;
public:
    B() { b = new int; cout << "B::B() is called.\n"; }
    ~B() { delete b; cout << "B::~B() is called.\n"; }
    void print() { cout << "B::print() is called.\n"; }
};

int main() {
    A * p = new B();
    delete p;

    return 0;
}

说明:

  1. 可以将子类指针(或引用)赋值给父类指针(或引用)
  2. 在构造子类对象时,会先构造父类对象,再构造对应的子类对象部分
  3. new新空间时,之后必须进行delete,否则会造成内存泄漏

代码运行结果:

A::A() is called.
B::B() is called.
A::~A() is called.

可以发现仅对B进行了构造,而没有进行析构,因此可能会造成内存泄漏。为了避免这一问题的发生,就需要引出一个新的知识点——虚析构函数。

虚析构函数

析构函数虚函数我们已经熟悉了,那么如何实现虚析构函数呢?顾名思义,只要把虚函数与虚构函数结合起来就行了。例如:

class A {
public: 
    A();  //构造函数
    virtual ~A();  //虚析构函数
    virtual void print();  //虚函数
};

可见,只要在原来的析构函数声明前加上virtual关键字就形成了虚析构函数。由此可以修改代码为:

#include <iostream>
using namespace std;

class A {
private: 
    int *a;
public: 
    A() { a = new int; cout << "A::A() is called.\n"; }
    virtual ~A() { delete a; cout << "A::~A() is called.\n"; }  //添加virtual关键字,形成虚析构函数
    void print() { cout << "A::print() is called.\n"; }
};

class B : public A {
private: 
    int *b;
public:
    B( int *t ) { b = new int; cout << "B::B() is called.\n"; }
    ~B() { delete b; cout << "B::~B() is called.\n"; }
    void print() { cout << "B::print() is called.\n"; }
};

int main() {
    int x = 1;
    A * p = new B( &x );
    delete p;

    return 0;
}

运行结果:

A::A() is called.
B::B() is called.
B::~B() is called.
A::~A() is called.

此时各个对象都会调用析构函数,问题也就解决了。

仅在基类声明为虚析构函数原因:

同普通虚函数一样,它的实现也需要维护一个虚函数表,在此基础上来根据对象类型来选择使用哪个虚构函数。以上面代码为例,由于p实际指向的是B类型的对象,又由于在基类声明了虚析构函数,因此会根据类型选择调用B的析构函数,同时由于在析构派生类时也会自动调用基类的析构函数,所以最终所有的对象都会被析构。

(并不是所有c++类都应该将析构函数设置为virtual。只有具有virtual函数的多态基类(或者其它想当base class的类)才应该将析构函数设置为virtual,对于普通的类则无必要。因为虚函数的实现要求对象携带额外信息,也就是维护一个指向虚函数表的指针vptr(virtual table pointer),vptr指向虚函数表vtbl(virtual table)。当调用一个对象的虚函数时,就会通过vptr找到vtbl,在vtbl中寻找正确的函数指针调用。由于vptr的加入,导致对象大小增加。所以对于非多态基类,没必要将析构函数声明为virtual以带来额外负担。 ——引用自https://www.cnblogs.com/zhuyf87/archive/2013/03/12/2955058.html

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/liushall/article/details/79947867

虚析构函数的实现原理

虚析构函数的理论前提是执行完子类的析构函数,那么父类的虚构函数必然会被执行。那么当用delete释放一个父类指针所实例化的子类对象时,如果没有定义析构函数,那么将只会调用父类的析构函数,而不会调用子类...
  • qq_23225317
  • qq_23225317
  • 2016-10-14 22:28:11
  • 1557

虚析构函数的使用(转载!)

一、当你的类准备给别人继承时要提供虚析构函数考虑下面例子:class A{public: A(){cout  ~A(){cout };class B : publi...
  • cffy625
  • cffy625
  • 2010-01-22 17:21:00
  • 12037

C++中虚析构函数的作用及其原理分析

参考http://blog.csdn.net/xiamentingtao/article/details/55517203 C++中的虚析构函数到底什么时候有用的,什么作用呢。 一.虚析构函数的...
  • derkampf
  • derkampf
  • 2017-03-15 00:13:04
  • 2893

个人对继承理解以及虚析构函数的理解

今天又从新研究了下继承和重载,感觉又有新的体会。         首先是对继承的理解,继承简单的说就是把基类的东西保留下来(一般都是public继承,这样基类中的public成员继承过来后还是pub...
  • Leeboy_Wang
  • Leeboy_Wang
  • 2012-02-26 20:47:00
  • 1906

C++学习之多态篇(虚函数和虚析构函数的实现原理--虚函数表)

通过下面的代码来说明: #include #include #include using namespace std; /**  *  定义动物类:Animal  *  成员函数:eat()...
  • hudfang
  • hudfang
  • 2016-01-26 18:13:55
  • 1898

基类的纯虚析构函数一定要予以实现

纯虚函数 纯虚函数是一种特殊的虚函数,在许多情况下,在基类中不能对虚函数给出有意义的实现,而把它声明为纯虚函数,它的实现留给该基类的派生类去做。这就是纯虚函数的作用。 虚函数是C++语言的精髓。含有纯...
  • friendbkf
  • friendbkf
  • 2015-05-17 18:59:49
  • 2380

什么时候要用虚析构函数?

 什么时候要用虚析构函数?通过基类的指针来删除派生类的对象时,基类的析构函数应该是虚的。否则其删除效果将无法实现。一般情况下,这样的删除只能够删除基类对象,而不能删除子类对象,形成了删除一半形象,从而...
  • redhat7890
  • redhat7890
  • 2009-11-16 17:21:00
  • 4779

纯虚析构函数必须给出定义

Effective C++ 条歀07:为多态基类声明virtual析构函数(Declare destructors virtual in polymorphic base classes) 纯虚函数...
  • wl1070325332
  • wl1070325332
  • 2017-03-08 17:18:48
  • 442

关于虚析构函数的作用和使用

作用:作为基类使用的类应该具有虚析构函数,以保证在删除基类指针(动态分配的对象)时,根据指针实际指向的对象进行适当的析构。 请看下面这段代码; #include class A{ publi...
  • wangbin_jxust
  • wangbin_jxust
  • 2014-10-15 14:59:43
  • 876

为什么基类中的析构函数要声明为虚析构函数?

题目 为什么基类中的析构函数要声明为虚析构函数? 解答 用对象指针来调用一个函数,有以下两种情况: 如果是虚函数,会调用派生类中的版本。如果是非虚函数,会调用指针所指类型的实现...
  • banbanlin
  • banbanlin
  • 2014-09-25 20:32:39
  • 4279
收藏助手
不良信息举报
您举报文章:虚析构函数
举报原因:
原因补充:

(最多只允许输入30个字)