问题聚焦:

不要在构造函数和析构函数中调用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》

转载于:https://www.cnblogs.com/suzhou/p/3638963.html

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

  1. 构造函数调用虚函数的问题

    一般情况下,不允许在构造函数或者析构函数中调用虚函数.其实语法上都没有问题,只是会失去多态性. 如果在构造函数中调用虚函数,会先调用父类中的实现,也就失去了多态的性质. class A {public ...

  2. C++构造函数调用虚函数的后果

    #include <iostream>class cx { public:virtual void func() {std::cout << "func" ...

  3. python构造函数调用成员函数_成员函数中的Python调用构造函数

    让我们以这个类为例,它正在扩展MySQLDB的connection对象.在class DBHandler(mysql.connections.Connection): def __init__(sel ...

  4. 构造函数调用虚函数先从子类搜索同名函数

    1 class X 2 { 3 X() 4 { 5 System.out.println("x"); // 6 vir(44); //看到vir会先搜索子类中的vir是否存在,如果 ...

  5. python构造函数调用成员函数_Python 子类构造函数调用

    super作用 如果子类(Puple)继承父类(Person)不做初始化,那么会自动继承父类(Person)属性name. 如果子类(Puple_Init)继承父类(Person)做了初始化,且不调用 ...

  6. Effective C++条款09:绝不在构造和析构过程中调用virtual函数

    Effective C++条款09:绝不在构造和析构过程中调用virtual函数(Never call virtual functions during construction or destruc ...

  7. 读书笔记 Effective C++: 02 构造析构赋值运算

    条款05:了解C++默认编写并调用的哪些函数 编译器会为class创建: 1. default构造函数(前提是:没有定义任何构造函数): 如果已经声明了一个构造函数,编译器就不会再创建default构 ...

  8. effective c++:virtual函数在构造函数和析构函数中的注意事项

    effective c++:virtual函数在构造函数和析构函数中的注意事项 如不使用自动生成函数要明确拒绝 对于一个类,如果你没有声明,c++会自动生成一个构造函数,一个析构函数,一个copy构造 ...

  9. 条款9:不要在构造和析构过程中调用virtual函数

    如下是一个股票交易的例子: 1 class Transaction // 交易的基类 2 { 3 public: 4 Transaction(); 5 virtual void logTransact ...

最新文章

  1. 关于ASP.NET MVC P5中CheckBox的HtmlHelper方法的bug。
  2. NetBeans 时事通讯(刊号 # 20 - Aug 11, 2008)
  3. 3D Computer Grapihcs Using OpenGL - 04 First Triangle
  4. android蓝牙pair,Android向更多蓝牙设备开放Fast Pair功能 配对更轻松了
  5. Makefile详解(六)
  6. Android AIDL Service 跨进程传递复杂数据
  7. 机械类常用英语(一.组装、冲压、喷漆等专业词汇)
  8. java docx4j 合并word_使用docx4j进行docx文档合并。
  9. 愿你一直能够撑下去!
  10. katacontainers v2编译
  11. 《machine learning in action》机器学习 算法学习笔记 决策树模型
  12. List<T>, IQueryable, IEnumerable 关系和区别
  13. 某易—将军令动态刨析算法(1)
  14. 程序实现蒙特卡洛算法计算PI值和积分
  15. 堪称「神器」的电脑软件
  16. 分布式游戏服务器通用架构的设计
  17. 微信浏览器 打开zip文件_愚蠢的怪胎技巧:使用7-Zip作为快速的文件浏览器
  18. MFC提示this application has requested the runtime to terminate it in an unusual way editbox框已经删了还在使用
  19. 基于单片机(AT89C51)的进制转换及进制计算器
  20. 「论文翻译」Predicting Drug-Target Interactions Using Weisfeiler-Lehman Neural Network

热门文章

  1. Write operations are not allowed in read-only mode (FlushMode.MANUAL)
  2. 【Elasticsearch】elasticsearch里面的关于批量读取mget的用法
  3. 【Elasticsearch】Elasticsearch性能调优
  4. 【mac】mac 安装nginx
  5. Linux : 文件处理命令
  6. kudu建表:Not enough live tablet servers to create a table with the requested replication factor 3. 2
  7. Integer的常用方法和String类型的常用方法
  8. mysql 重置自增长_怎么重置mysql的自增列AUTO_INCREMENT初时值
  9. 避免线上故障的10条建议
  10. 从入门到入土(八)RocketMQ的Consumer是如何做的负载均衡的