#include <iostream> using namespace std; class Person { public: virtual ~Person() //加了virtual,讲析构函数声明为虚函数 { cout << "Person::~Person()" << endl; } }; class Student : public Person { public: ~Student() // virtual可加可不加 { cout << "Student::~Student()" << endl; } }; int main() { Person *pt1 = new Person; Person *pt2 = new Student; // 用基类的指针指向子类 // Student *pt3 = new Person; // 不能用子类指针指向基类,错误! Student *pt4 = new Student; delete pt1; cout << "*********" << endl; delete pt2; cout << "*********" << endl; //delete pt3; //cout << "*********" << endl; delete pt4; cout << "*********" << endl; return 0; }
运行结果:
Person::~Person() *********** Student::~Student() Person::~Person() ********** Student::~Student() Person::~Person() ********** 如果在基类中析构函数不加virtual,结果为: Person::~Person() *********** Person::~Person() ********** Student::~Student() Person::~Person() **********
可以看出:只有在用基类的指针指向派生类的时候,才会出现这种情况。因为这个时候虚函数发挥了动态的作用。
析构函数执行时先调用派生类的析构函数,其次才调用基类的析构函数。如果析构函数不是虚函数,而程序执行时又要通过基类的指针去销毁派生类的动态对象,那么用delete销毁对象时,只调用了基类的析构函数,未调用派生类的析构函数。这样会造成销毁对象不完全。
如果在上面的例子中,基类中未定义virtual析构函数,而派生类中定义了virtual的析构函数,此时用基类指针指向派生类,再delete掉,
即:
1 class Person 2 { 3 public: 4 ~Person() 5 6 { 7 cout << "Person::~Person()" << endl; 8 } 9 }; 10 11 class Student : public Person 12 { 13 public: 14 virtual ~Student() 15 16 { 17 cout << "Student::~Student()" << endl; 18 } 19 }; 20 21 22 23 Person * pt = new Student; 24 25 delete pt;
运行结果会出错。
反正是只要基类析构没有定义为virtual,而派生类(可能有多层)中有把析构定义为virtual的,此时用基类的指针指向派生类,再delete,会出错。
而:
1 class Person 2 { 3 public: 4 ~Person() 5 { 6 cout << "Person::~Person()" << endl; 7 } 8 }; 9 10 class Student : public Person 11 { 12 public: 13 virtual ~Student() 14 { 15 cout << "Student::~Student()" << endl; 16 } 17 }; 18 19 class OneSt : public Student 20 { 21 public: 22 ~OneSt() 23 { 24 cout << "OneSt::~OneSt()" << endl; 25 } 26 }; 27 28
如果用
1 Student * pt = OneSt; 2 3 delete pt;
运行结果为:
1 OneSt::~OneSt() 2 3 Student::~Student() 4 5 Person::~Person()
是可以运行的。
Effective C++ (第7条:要将多态基类的析构函数声明为虚函数)
需要记住的
- 应该为多态基类声明虚析构器。一旦一个类包含虚函数,它就应该包含一个虚析构器。
- 如果一个类不用作基类或者不需具有多态性,便不应该为它声明虚析构器。