目录
一.习题1: 解决下列测试代码所出现的问题
class Person {
public:
~Person() {
cout << "~Person()析构函数: " <<_p<< endl;
delete[] _p;
}
public:
int* _p=new int[10];
};
class Student :public Person {
public:
~Student() {
cout << "~Student()析构函数: "<<_s<< endl;
delete[] _s;
}
public:
int* _s=new int[20];
};
在上方代码中有一对父子类,父子类各有一个指向堆区空间的整型指针成员变量,那么意味着创建类对象会开辟空间。在这两个类中,都各有一个显式的析构函数。
测试用例1:
int main() {
Person p1;
Student s1;
return 0;
}
在测试用例中,创建了两个父子类对象。
运行结果:
由上图结果可知:结果显示很正常,s1是子类对象,继承了父类的成员变量,那么析构的时候需要调用父类的析构函数,没什么问题。
测试用例2:
int main(){
Person* ptr1 = new Person;
Person* ptr2 = new Student;
delete ptr1;
delete ptr2;
return 0;
}
在这个测试用例中,父类创建了两个指针对象,分别指向Person类型的堆区空间和Student类型的堆区空间。由于new了堆区空间,肯定需要释放了这两个指针指向的堆区空间。
运行结果:
通过结果可知,ptr1指针对象的释放没啥问题,因为ptr1开辟的是Person类的空间,那么肯定会调用Person类的析构函数;而ptr2指针对象的释放出现了问题:它只析构了它自己,没有释放Student类的堆区空间,因为释放Student类的堆区空间会调用其析构函数,但结果显示没有调用!于是出现了内存泄漏。
主要原因:当父类指针指向子类的时候(Person* ptr2=new Student),若父类析构函数不声明为虚函数,在编译器delete时,只会调用父类而不会调用子类的析构函数,从而导致内存泄露。!!!!!
通过之前学习多态特性我们了解到:普通调用是和调用对象的类型有关,那么编译器认为我们创建的Person类两个指针对象在delete时,采用的是普通调用,所以调用的依据是与调用对象ptr2的类型(Person)有关,所以编译器就只调用了Person类的析构函数;
而我们真实想要采用的是多态调用,所谓多态调用的依据是指针(ptr2)或者引用与指向的对象(new Student)有关。
所以需要在父类和子类的析构函数上加上virtual,让析构函数变成虚析构,这样编译器就认定我们采用的是多态调用了!!!