C++虚析构函数

在C++中,当涉及继承时,基类的析构函数应声明为虚函数,以确保正确销毁子类对象,避免内存泄漏。非虚析构函数只会调用基类的析构,导致子类资源未被释放。构造函数不应为虚函数,因为其在对象实例化之前调用,此时无法通过虚函数表调用。本文通过实例展示了虚析构函数的重要性,并探讨了其背后的多态原理。
摘要由CSDN通过智能技术生成

Q:C++中析构函数能不能是虚函数?

A:我是最近才注意到这个问题,首先是笔试的时候遇到过,当时根本不会,后来去查了一下,一知半解,大都说析构函数常常为虚函数,还有的人说必须是,后来面试的时候面试官正好问了,我也没讲太清楚,所以觉得有必要再重新梳理一下。

严谨的说,C++在有继承发生的时候,必须要把基类的析构函数写为虚函数,如果不这么做,在释放资源时,只会释放基类的资源,而不会释放子类的,造成内存泄漏。但是如果是没有继承,那就完全没必要把析构函数写为虚函数了,因为我们知道,对于有虚函数的类,C++都会为其分配一个虚函数表,这样做就会造成内存不必要的开销。

下面举例子来说明:

class Base
{
public:
	Base()
	{
		cout << "Base的构造函数被执行" << endl;
	}
	~Base()
	{
		cout << "Base的析构函数被执行" << endl;
	}
};

class Derived : public Base
{
public:
	Derived()
	{
		cout << "Derived的构造函数被执行" << endl;
	}
	~Derived()
	{
		cout << "Derived的析构函数被执行" << endl;
	}
};

int main()
{
	Derived* d = new Derived;
	delete d;
	return 0;
}

可以看到,当用一个子类的指针去指向子类对象时,此时,不把基类析构写为虚函数也无妨。(子类和基类的析构函数都得到了调用)

但是当用父类的指针去指向子类对象时侯呢?看代码:

class Base
{
public:
	Base()
	{
		cout << "Base的构造函数被执行" << endl;
	}
	~Base()
	{
		cout << "Base的析构函数被执行" << endl;
	}
};

class Derived : public Base
{
public:
	Derived()
	{
		cout << "Derived的构造函数被执行" << endl;
	}
	~Derived()
	{
		cout << "Derived的析构函数被执行" << endl;
	}
};

int main()
{
	Base* d = new Derived;
	delete d;
	return 0;
}

 可以明显的看到,只有基类的析构函数被执行了,这样就会造成内存泄露,是不合理的。

总结:

其实之所以C++要这么做,原因很简单,就是因为在有多态技术的前提下,我们用父类的指针去指向子类对象时侯,其实是希望调用的子类的函数,但是我们如果事先并没有把该函数声明为虚函数的话,那最终调用的还只是父类的方法而已。如果我们希望调用子类的方法,那么就势必要把该方法在父类中声明为虚函数,这样做既析构了父类,又析构了子类,一箭双雕,何乐不为呢?

构造函数不能为虚函数

1. 存储空间角度:虚函数对应一个vtable,vtable存储于对象的内存空间,若构造函数是虚的,则需要通过 vtable来调用,若对象还未实例化,即内存空间还没有,无法找到vtable;

2. 使用角度:虚函数主要用于在信息不全的情况下,能使重载的函数得到对应的调用。构造函数本身就是要初始化实例,那使用虚函数就没有实际意义;

3. 从实际含义上看,在调用构造函数时还不能确定对象的真实类型(因为子类会调父类的构造函数);而且构造函数的作用是提供初始化,在对象生命期只执行一次,不是对象的动态行为,也没有太大的必要成为虚函数。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值