我们用派生类声明出对象的时候,即使不把析构函数定义成虚函数,析构派生类对象的时候,也会自动调用基类的析构函数。这样看来我们似乎不需要将析构函数定义成虚函数,也不存在什么问题。
class Person{
public:
~Person()
{
cout << "~Person" << endl;
}
};
class Student :public Person
{
public:
~Student()
{
cout << "~Student" << endl;
}
};
int main(){
Person p;// ~Person
Student s;// ~Student ~Person
Person rp = s;//~Person
return 0;
}
我们接下来在看一个场景:我们用基类的指针去接收用new申请的基类对象的空间,同样派生类也是如此,当我们不需要在使用这个指针的时候,delete掉,防止内存泄漏。delete的时候我们希望这个空间上的对象调用自己的析构函数,完成空间的释放。
class Person{
public:
~Person()
{
cout << "~Person" << endl;
}
};
class Student :public Person
{
public:
~Student()
{
cout << "~Student" << endl;
}
};
int main(){
Person* p = new Person;
delete p;
Student* s = new Student;
delete s;
return 0;
}
似乎这种场景下,析构函数不定义为虚函数,最后的结果也符合我们的期望,也没有内存泄漏问题。
然而在这个场景下:用基类指针去接收申请的包含派生类对象的空间,当这个指针完成任务之后,我们需要delete掉,防止内存泄漏,我们期望空间中的对象调用自己的析构函数,完成空间的释放,然后事实是?让我们看一下代码。
class Person{
public:
~Person()
{
cout << "~Person" << endl;
}
};
class Student :public Person
{
public:
~Student()
{
cout << "~Student" << endl;
}
};
int main(){
Person* p = new Student;
delete p;
return 0;
}
我们发现在这种场景下,达不到我们的预期。程序只析构了基类,并没有析构派生类,造成了内存泄漏。
此时我们便需要将析构函数定义为虚函数,以达到我们的预期,完成空间的释放,并且不会造成内存泄漏问题。
class Person{
public:
virtual ~Person()
{
cout << "~Person" << endl;
}
};
class Student :public Person
{
public:
virtual ~Student()
{
cout << "~Student" << endl;
}
};
int main(){
Person* p = new Student;
delete p;
return 0;
}
总之:在公有继承中,基类对派生类及其对象的操作,只能影响到那些从基类继承下来的成员。如果想要用基类对非继承成员函数进行操作,则要把基类的这个函数定义为虚函数。
析构函数自然也应该如此:如果它想析构子类中的重新定义或新的成员及对象,当然也应该把函数定义为虚函数。