C++中构造函数和析构函数是否可以是虚函数,为什么?

本文探讨了为什么构造函数不能是虚函数,主要是因为对象在构造过程中尚未完全形成,无法提供虚函数表指针。而析构函数可以是虚函数,以确保通过基类指针正确地销毁子类对象,防止内存泄露。不声明析构函数为虚函数可能导致只有基类部分被销毁,子类部分内存未释放。通过示例展示了虚析构函数在多态调用中的重要性。
摘要由CSDN通过智能技术生成

构造函数和析构函数是否可以是虚函数,为什么?

1. 为什么构造函数不能为虚函数?

虚函数的调用需要虚函数表指针,而该指针存放在对象的内容空间中;若构造函数声明为虚函数,那么由于对象还未创建,还没有内存空间,更没有虚函数表地址用来调用虚函数——构造函数了。

2. 为什么析构函数可以为虚函数,如果不设为虚函数可能会存在什么问题?

首先析构函数可以为虚函数,而且当要使用基类指针或引用调用子类时,最好将基类的析构函数声明为虚函数,否则可以存在内存泄露的问题。

举例说明:

子类B继承自基类A;A *p = new B; delete p;

1) 此时,如果类A的析构函数不是虚函数,那么delete p;将会仅仅调用A的析构函数,只释放了B对象中的A部分,而派生出的新的部分未释放掉。

2) 如果类A的析构函数是虚函数,delete p; 将会先调用B的析构函数,再调用A的析构函数,释放B对象的所有空间。

补充: B *p = new B; delete p;时也是先调用B的析构函数,再调用A的析构函数。

#include <iostream>
using namespace std;

class A
{};

class B:public A
{};

class Base
{
public:
	Base(void)
	{
		cout << "我是Base类的构造函数" << endl;
	}

 	~Base(void)
	{
		cout << "我是Base类的析构函数" << endl;
	}
	virtual A* func(void)
	{
		cout << "我是Base类的虚函数" << endl;
	}
};

class Test:public Base
{
public:
	Test(void)
	{
		cout << "我是Test类的构造函数" << endl;
	}
	
	~Test(void)
	{
		cout << "我是Test类的析构函数" << endl;
	}
	//它可以覆盖负累中的虚函数
	B* func(void)
	{
		cout << "我是Test类的函数func" << endl;
	}
};

void test(Base* b)
{
	b->func();
}

int main(int argc,const char* argv[])
{
	Base* t = new Test;
	cout << "----------" << endl;
	test(t);
	cout << "----------" << endl;
	delete t;
	//test(new Base);
}

上面可以说是多态的一种运用,用父类指针来指向子类对象,然后调用被覆盖函数。

输出:

当父类中的析构函数~Base(void)没有加virtual关键字时,在释放内存时只会调用父类的虚函数释放父类占用的内存,而子类Test的虚函数并没有被调用,这就会导致内存泄露,没有及时得到释放。

我是Base类的构造函数
我是Test类的构造函数


我是Test类的函数func


我是Base类的析构函数

此时的结果为父类中的析构函数~Base(void)加virtual关键字后,也调用了子类的虚函数。

我是Base类的构造函数
我是Test类的构造函数


我是Test类的函数func


我是Test类的析构函数
我是Base类的析构函数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值