c++虚析构和纯虚析构

c++中不能声明构造函数,但是可以声明虚析构函数和纯虚析构函数。

 

虚析构和纯虚析构

纯虚析构的使用场景:多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码。(1.父类指针指向子类对象,2.子类在堆区有数据)

解决方式:将父类中的析构函数改为虚析构或者纯虚析构

虚析构和纯虚析构共性:

  • 可以解决父类指针释放子类对象
  • 都需要有具体的函数实现

虚析构和纯虚析构区别:

  • 如果是纯虚析构,该类属于抽象类,无法实例化对象

虚析构语法:

virtual ~类名(){}

纯虚析构语法:

virtual ~类名() = 0;

类名::~类名(){}

示例:

一:我们先不设置为虚函数:

#include
using namespace std;
class base {
public:
	~base() {
		cout << "父类析构函数被调用" << endl;
	}
};
class derived :public base{
public:
	int* p;
	derived() {
		p = new int(2);
	}
	~derived() {
		cout << "子类的析构函数被调用" << endl;
		delete p;
	}
};
void fun(base* ptr) { //fun函数把传入的指针p指向的堆区数据给释放掉
	delete ptr;
}
int main() {
	base* b = new derived();
	fun(b);
	return 0;
}

c++虚析构和纯虚析构_第1张图片

这个说明,通过基类指针删除派生类对象的时候调用的是基类的析构函数,但是我子类的析构函数却没有被调用,这样就造成了子类动态分配的内存无法释放掉,造成了内存泄漏。也就是说派生类对象成员p所指向的内存空间,在对象消亡之后既不能被本程序继续使用,也么有被释放掉。对于内存需求量大,长时间连续运行的大程序来讲,这样会浪费相当多的内存,相当危险,所有如果子类有动态内存分配,一定要把基类的析构函数设置为虚函数。

 

二:当我们把父类的析构函数设置为虚函数之后,

virtual ~base() {
        cout << "父类析构函数被调用" << endl;
    }

c++虚析构和纯虚析构_第2张图片

可以看出:

当把父类的析构函数设置为析构函数之后,就可以调用子类的析构函数,这样就可以把子类创建的堆区数据给释放掉。 

 因为  C++明确指出,当子类对象经由一个父类指针被删除,而该父类带有一个non-virtual析构函数,其结果未定义--实际执行时通常发生的是对象的derived成分没有被销毁。子类的析构函数也未能被执行。这就造成了内存泄漏的危险。

 

总结:

​ 1. 虚析构或纯虚析构就是用来解决通过父类指针释放子类对象

​ 2. 如果子类中没有堆区数据,可以不写为虚析构或纯虚析构

​ 3. 拥有纯虚析构函数的类也属于抽象类

你可能感兴趣的:(c++,抽象类,多态)