Effective C++(9) 构造函数调用virtual函数会发生什么

问题聚焦:
不要在构造函数和析构函数中调用virtual函数,因为这样的调用不会带来你预想的结果。

让我先来看一下在构造函数里调用一个virtual函数会发生什么结果
Demo

class Transaction {
public:
 Transaction();
 virtual void logTransaction() const = 0;
};
Transaction::Transaction()
{
 logTransaction();
}
//void Transaction::logTransaction() const      //第一次编译时,注释掉该段代码
//{
//	std::cout << "Transaction called" << std::endl;
//}
class BuyTransaction: public Transaction
{
public:
 virtual void logTransaction() const;
};
void BuyTransaction::logTransaction() const
{
 std::cout << "BuyTransaction called" << std::endl;
}

//执行下面的语句会发生什么事情?
BuyTransaction b;


执行上述代码,会发现链接出错,报错:



表示没有Transaction::logTransaction() const的实现。
现在把上述代码中被注释的代码补上之后,再编译一次,OK,通过了。来看看结果是什么吧


不错,运行正常,也没有crash。不过,貌似不是我们想要的结果。
我们是对BuyTransaction类进行实例化,但是构造函数调用的是父类的构造函数,这是为什么呢?

下面我们来分析一下原因:
  1. 父类构造函数先调用,此时子类的局部成员变量还没准备好,这时如果将virtual函数下降至子类阶层,那么使用未初始化的部分可能会引起不明确的行为,所以C++直接禁止了这种行为,因此会出现上面的链接错误。
  2. 在子类的父类部分被构造期间,virtual函数并不认为是virtual函数,因为在初始化子类的父类部分时,编译器认为当前的对象是父类型,同时,直接认为子类部分是不存在的,因为子类成分并没有被初始化。

问题很明显了,就是在构造函数和析构函数中调用了virtual函数导致了上面的问题。那么有什么解决方案呢?
解决方案:令子类将必要的构造信息向上传递至base class构造函数
Demo

/** main.h **/
#include<iostream>
#include<string>
class Transaction {
public:
 explicit Transaction(const std::string& logInfo);
 void logTransaction(const std::string& logInfo) const;   // 不再是虚函数
};
Transaction::Transaction(const std::string& logInfo)
{
 logTransaction(logInfo);
}
void Transaction::logTransaction(const std::string& logInfo) const
{
 std::string s = logInfo;
 std::cout << s << std::endl;
}
class BuyTransaction: public Transaction
{
public:
 BuyTransaction(const std::string& logInfo);
};
BuyTransaction::BuyTransaction(const std::string& logInfo):Transaction(logInfo)    // 把信息传递给父类,通过父类打印出log
{
 std::cout << "BuyTransaction called" << std::endl;
}

/** main.cpp **/
#include<iostream>
#include"main.h"
int main()
{
 BuyTransaction b("hello world");
 system("Pause");
 return 0;
}


打印结果:


这是我们想要的结果。

小结:
在构造和析构函数内不要调用virtual函数,因为这类调用不下降至子类。


参考资料:
《Effective C++ 3rd》


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值