目录
虚析构函数的作用
需求场景:需要一个基类指针去释放子类对象 。
即:通过父类指针,释放所有子类资源。
先举个案例,创建一个类A,在其中有个私有属性"*p",有构造、析构函数:
class A
{
public:
A()
{
p = new char[20];
strcpy(p, "obja");
printf("A()\n");
}
~A()
{
delete [] p;
printf("~A()\n");
}
protected:
private:
char *p;
};
再用A类做父类,创建一个B类:
class B : public A
{
public:
B()
{
p = new char[20];
strcpy(p, "objb");
printf("B()\n");
}
~B()
{
delete [] p;
printf("~B()\n");
}
protected:
private:
char *p;
};
再用B类做父类,创建一个C类:
class C : public B
{
public:
C()
{
p = new char[20];
strcpy(p, "objc");
printf("C()\n");
}
~C()
{
delete [] p;
printf("~C()\n");
}
protected:
private:
char *p;
};
创建一个调用析构函数的全局函数:
void howtodelete(B *base)
{
delete base; //这句话不会表现成多态 这种属性
}
那么来进行调用:
void main()
{
C *myC = new C;
cout<<"hello..."<<endl;
system("pause");
return ;
}
运行发现:
程序只执行了A类的析构函数,其他的都没有执行。 这样,就存在内存泄漏发生了,因为B和C所占用的内存,都没有被析构掉啊!换句话说,在这种场景下,只执行了最原始的父类的析构函数,这是因为,在函数"howtodelete"将不会表现出多态,它只会按你所传的类型,去执行A类的析构函数。所以说,在这种场景下,只会调用父类的析构函数,造成内存泄漏。
如果想通过父类指针把所有的子类对象的析构函数都执行一遍,就需要用到虚析构函数了。即在最原始的类中的析构函数,加一个虚函数关键字"virtual"就可以了!
定义在最原始的父类中的析构函数前加"virtual"关键字:
virtual ~A()
{
delete [] p;
printf("~A()\n");
}
定义在由最原始的父类中继承的子类的析构函数前加"virtual"关键字:
~B()
{
delete [] p;
printf("~B()\n");
}
定义在由从父类中继承的子类的析构函数前加"virtual"关键字:
~C()
{
delete [] p;
printf("~C()\n");
}
运行结果,完美:
话说回来,如果是直接通过子类对象的析构函数来释放资源的,是不需要虚析构函数的,直接写就行了!只有不得不通过父类指针去析构子类资源的场景下,才需要虚析构函数的。
总体代码
dm15_虚析构函数.cpp
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
//虚析构函数
class A
{
public:
A()
{
p = new char[20];
strcpy(p, "obja");
printf("A()\n");
}
virtual ~A()
{
delete [] p;
printf("~A()\n");
}
protected:
private:
char *p;
};
class B : public A
{
public:
B()
{
p = new char[20];
strcpy(p, "objb");
printf("B()\n");
}
~B()
{
delete [] p;
printf("~B()\n");
}
protected:
private:
char *p;
};
class C : public B
{
public:
C()
{
p = new char[20];
strcpy(p, "objc");
printf("C()\n");
}
~C()
{
delete [] p;
printf("~C()\n");
}
protected:
private:
char *p;
};
//只执行了 父类的析构函数
//向通过父类指针 把 所有的子类对象的析构函数 都执行一遍
//向通过父类指针 释放所有的子类资源
void howtodelete(A *base)
{
delete base; //这句话不会表现成多态 这种属性
}
/*
void howtodelete(B *base)
{
delete base; //这句话不会表现成多态 这种属性
}
*/
void main()
{
C *myC = new C; //new delete匹配
//
delete myC; //直接通过子类对象释放资源 不需要写virtual
//howtodelete(myC);
cout<<"hello..."<<endl;
system("pause");
return ;
}