9. 虚析构函数

如果一个类可能被继承,并且会通过基类指针来删除(delete)派生类的对象,那么他的析构函数必须是虚函数。否则只会调用基类的析构函数,不会调用派生类的析构函数,导致部分资源泄露。

虚析构函数的作用是保证在使用 delete 来销毁对象是一定能够调用该类的析构函数来防止资源丢失。

语法

class 类名{
    // 声明虚析函数。
    virtual ~类名(void){...}
};

示例

// filename: v_decons.cpp
#include <iostream>

using namespace std;

#define PI (3.1415926)
// 抽象类 
class Shape{ // 抽象类(Abstract Class);
    public:
        virtual ~Shape() {cout << "~Shape()" << endl;};
        // 纯虚函数的声明
        virtual void moveTo(float x, float y)=0; 
};
// 点类(描述一个点的位置,面积等信息)
class Point: public Shape {
    public:
        Point(float ax=0, float ay=0):x(ax), y(ay) {
            cout << "Point(" << x << "," << y << ")\n";
        }
        ~Point() {
            cout << "~Point(" << x << "," << y << ")\n";
        }
        void moveTo(float new_x, float new_y) {
            x = new_x; y = new_y;
        }
    public:
        float x;
        float y;
};
// 圆类(描述圆的位置、半径、面积等信息)
class Circle : public Point {
    public:
        Circle(float ax, float ay, float radius)
            : Point(ax, ay), r(radius) {
            cout << "Circle(" << x << "," << y << "," << r << ")\n";
        }
        ~Circle() {
            cout << "~Circle(" << x << "," << y << "," << r << ")\n";
        }
    public:
        float r; // 半径
};

int main(int argc, char * argv[]) {
    Point * p;
    p = new Point(1, 2);
    delete p;
    Shape *p2;
    p2 = new Circle(3, 4, 5);
    delete p2; // 调用圆的析构函数

    cout << "程序结束!" << endl;
    return 0;
}

编译和运行结果如下:

weimz@mzstudio:~$ g++ -o v_decons v_decons.cpp
weimz@mzstudio:~$ ./v_decons 
Point(1,2)
~Point(1,2)
Point(3,4)
Circle(3,4,5)
~Circle(3,4,5)
~Point(3,4)
程序结束!

实验

将上述示例的抽象类 Shape 的 虚析构函数 virtual ~Shape(){...} 改为 ~Shape(){...}, 然后运行此示例,查看器运行结果,想想为什么?