条款9:绝不在构造函数和析构函数中调用virtual 函数

本文探讨了在C++中为何不应在构造函数和析构函数中调用virtual函数。通过实例说明了这种做法可能导致的问题,并提供了解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

条款9:绝不在构造函数和析构函数中调用virtual 函数

1、在构造函数中调用virtual 函数

 先看段代码,书中的例子,修改了下
class Transaction
{
public:
	Transaction() {LogTransaction();}
	virtual void LogTransaction()
	{
		cout<<"Trasaction Log \n";
	}
};

class BuyTransaction : public Transaction
{
public:
	void LogTransaction() 
	{
		cout<<"BuyTransaction Log \n";
	}
};
调用
BuyTransaction b;
结果
Trasaction Log

    通过结果可以看出不是我们想要的。BuyTransaction b,这里BuyTransaction 构造函数会被调用,但会先调用基类Trasaction的构造函数,但该构造函数里面调用一个virtual 函数,意向是调用子类的LogTransaction函数,但实际上子类还没有开始构造,即对象还没有在内存中形成,对象的所有成员还没有定义,因此编译器不会让这样不可意料的事情发生,规定:base class构造期间virtual函数绝对不会下降到derived class型阶层,即在该阶段对象时隶属base class的,调用的virtual 函数不是virtual 函数。
    在书中还有另一种说法,在derived class对象的base class构造期间,对象的类型是base class而不是derived class。不只virtual函数会被编译器解析至(resolve to)base class,若使用运行期类型信息,也会把对象视为base class类型。因为“derived 专属成分”尚未初始化,因此:对象在derived class构造函数开始执行前不会成为一个derived class对象。

2、在析构函数中调用virtual 函数

    其结果和解释都可以跟上面一样,基类的析构函数中调用virtual 函数,结果还是调用基类的函数,因为析构函数的行为时:先调用子类的析构函数,再到基类,子类析构后,子类的所有成员均为未初始化,因此,进入基类的析构函数后对象就成为一个基类对象。

如何解决上面的问题呢?将virtual 函数修改为non-virtual 函数,在子类中构造函数中传入对应的值。
class Transaction
{
public:
	Transaction(const std::string &strLog) {LogTransaction(strLog);}
	void LogTransaction(const std::string &strLog)
	{
		cout<<"Trasaction Log :"<<strLog<<endl;
	}
};

class BuyTransaction : public Transaction
{
public:
	BuyTransaction(const std::string &strLog) : Transaction(strLog)
	{
	}
};

记住
在构造和析构期间不要调用virtual函数,因为这类调用从不下降至derived class(比起当前执行构造和析构函数的那层)。



     
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值