前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C++编程经验(4):不要在构造函数和析构函数中使用虚函数

C++编程经验(4):不要在构造函数和析构函数中使用虚函数

作者头像
看、未来
发布2021-09-18 11:43:20
1.3K0
发布2021-09-18 11:43:20
举报
文章被收录于专栏:CSDN搜“看,未来”

这个事情呢,其实我们平时也不会去做的,对吧。 当然要是做了的话,那也可以做好某些天连夜加班的准备。


构造函数中调用虚函数

首先构造函数中不能调用虚函数,不是说语法不允许,最重要的原因在于,当有继承的时候,父类会调用到子类的函数,但是此时子类并没有初始化,会导致数据错误,就这一点足已让你不能在构造函数中调用虚函数。

在基类的构造过程中,虚函数调用从不会被传递到派生类中。代之的是,派生类对象表现出来的行为好象其本身就是基类型。不规范地说,在基类的构造过程中,虚函数并没有被"构造"。

简单的说就是,在子类对象的基类子对象构造期间,调用的虚函数的版本是基类的而不是子类的。

对上面这种看上去有点违背直觉的行为可以用一个理由来解释:因为基类构造器是在派生类之前执行的,所以在基类构造器运行的时候派生类的数据成员还没有被初始化。如果在基类的构造过程中对虚函数的调用传递到了派生类, 派生类对象当然可以参照引用局部的数据成员,但是这些数据成员其时尚未被初始化。这将会导致无休止的未定义行为和彻夜的代码调试。沿类层次往下调用尚未初始化的对象的某些部分本来就是危险的,所以C++干脆不让你这样做。

代码语言:javascript
复制
#include <iostream>
using namespace std;
class A
{
public:
	A()
	{ 
		cout << "A构造函数";
		Test();
	}
	~A()
	{
		cout << "A析构函数";
		cout << "A::Test()" << endl;
	}
	virtual void Test()
	{
		cout << "A::Test()" << endl;
	}
};
 
class B:public A
{
public:
	B()
	{
		cout << "B构造函数";
		Test();
	}
	~B()
	{
		cout << "B析构函数";
		Test();
	}
	virtual void Test()
	{
		cout << "B::Test()" << endl;
	}
};
 
int main()
{
	A* pA = new B();
	cout << "动态调用:";
	pA->Test();
 
	delete pA;
	return 0;
}

对于这段代码,可能会执行出结果来,但是不要过于庆幸,新版的编译器会拒绝你在构造函数中调用了虚函数,然后帮你调整了方向。。。 因为编译器不这么做就导致你不确定的数据错误。

对于这个问题,看到一个很nice的说法:在一些平台正常,在另一些平台未必正常。今天正常,以后未必正常。


析构函数中调用虚函数

在对象的析构期间,存在与上面同样的逻辑。一旦一个派生类的析构器运行起来,该对象的派生类数据成员就被假设为是未定义的值,这样以来,C++就把它们当做是不存在一样。一旦进入到基类的析构器中,该对象即变为一个基类对象,C++中各个部分(虚函数,dynamic_cast运算符等等)都这样处理。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021/08/02 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 构造函数中调用虚函数
  • 析构函数中调用虚函数
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档