条款9:不要在构造和析构过程中调用virtual函数
如下是一个股票交易的例子:
1 class Transaction // 交易的基类 2 { 3 public: 4 Transaction(); 5 virtual void logTransaction() const = 0; // 用于记录交易日志 6 }; 7 Transaction::Transaction() 8 { 9 logTransaction(); // 调用虚函数 10 } 11 12 class BuyTransaction : public Transaction // 买进股票 13 { 14 virtual void logTransaction() const; 15 }; 16 void BuyTransaction::logTransaction() const{ } 17 18 class SellTransaction : public Transaction // 卖出股票 19 { 20 virtual void logTransaction() const; 21 }; 22 void SellTransaction::logTransaction() const{ } 23 24 int main() 25 { 26 BuyTransaction b; 27 28 return 0; 29 }
上述代码中执行BuyTransaction b时,会调用基类的构造函数,而基类的构造函数会调用一个虚函数来完成工作。但是该虚函数是否会调用派生类的对应函数呢?答案是否定的,解释如下:
1> 基类的构造是先于派生类的构造的。当基类的构造函数执行时,派生类中的成员尚未被初始化,如果允许基类构造期间调用派生类的函数,可能也会调用了没有初始化的“垃圾值”,导致不确定行为发生。
2> 基类构造期间,virtual函数的行为绝对不会伸到派生类中,因为此时构造的是基类,即此时构造的对象的类型是基类而非派生类,这点很重要。
但是有时我们在构造基类的时候又需要派生类中才有的参数信息,如何解决:
在基类中将logTransaction函数改为非虚函数,然后在构造派生类时将必要的参数传递到基类的构造函数中去,像如下这样:
1 #include <string> 2 3 class Transaction // 交易的基类 4 { 5 public: 6 explicit Transaction(const std::string& logInfo); 7 void logTransaction(const std::string& logInfo) const; // 用于记录交易日志 8 }; 9 Transaction::Transaction(const std::string& logInfo) 10 { 11 logTransaction(logInfo); // 调用非虚函数12 } 13 void Transaction::logTransaction(const std::string& logInfo) const{ } 14 15 class BuyTransaction : public Transaction // 买进股票 16 { 17 public: 18 BuyTransaction(const std::string& parameter) : Transaction(parameter){ } 19 }; 20 21 22 int main() 23 { 24 BuyTransaction b("BT"); 25 26 return 0; 27 }
由上可知,如果基类构造时要使用派生类的信息,可以通过派生类构造函数的初始化列表传入相关参数,切不可调妄图调用虚函数实现,因为在构造基类期间其对象的类型是基类类型。
对于析构函数也是同样的道理,基类的析构总是在派生类析构后才进行,此时派生类的对象已经不存在了,而调用虚函数必然会引发一个不确定行为。当然你也可以将基类的虚函数实现后在析构函数中进行调用,但是这样的话,为什么不定义为非虚函数呢,虚函数的意义将不复存在了。
转载于:https://www.cnblogs.com/benxintuzi/p/4527948.html
条款9:不要在构造和析构过程中调用virtual函数相关推荐
- Effective C++条款09:绝不在构造和析构过程中调用virtual函数
Effective C++条款09:绝不在构造和析构过程中调用virtual函数(Never call virtual functions during construction or destruc ...
- C++绝不在构造和析构过程中调用virtual函数
绝不在构造和析构过程中调用virtual函数 如果希望在继承体系中根据类型在构建对象时表现出不同行为,可以会想到在基类的构造函数中调用一个虚函数: class Transaction { //所有交易 ...
- 关于构造与析构过程中调用虚函数的问题
今天面试碰到一个构造函数与析构函数中调用需虚函数的问题,当时不太确定,回来敲了一下,发现确实表现的不一样,在网上一查发现另有玄机. 代码: # gcc version 4.8.2 (Ubuntu 4. ...
- 绝不要在构造函数和析构过程中调用virtual函数
下面是一个用来塑模股市交易的类: derived的类的构造函数被调用,但是首先得调用基类Transaction的构造函数,但是在后面还得调用virrual函数,这个时候子类的对象的构造还没有完成,那么 ...
- 开机启动加载驱动过程中调用PostMessage函数出错
今天在WINCE5.0+S3C2440系统调试检测出租车是否载客的驱动的时候遇到这样的问题: 发现在开机启动加载驱动过程中调用PostMessage函数时会导致调用的线程崩溃,比如如果下面的线程在创建 ...
- OpenCV 相机校正过程中,calibrateCamera函数projectPoints函数的重投影误差的分析
OpenCV 校正过程中,calibrateCamera函数的ret和重投影误差的分析 OpenCV对相机进行校正的过程中,校正返回值retval和重投影误差的计算公式表示和分析. OpenCV 校正 ...
- 只能在执行 Render() 的过程中调用 RegisterForEventValidation
当用GridView导出Execl的时候,会发生只能在执行 Render() 的过程中调用 RegisterForEventValidation的错误提示.有两种方法可以解决以上问题: 1.修改web ...
- 异常“只能在执行Render()的过程中调用RegisterForEventValidation”的解决办法(转)...
当出现下面的异常的时候: 只能在执行Render()的过程中调用RegisterForEventValidation 当出现的异常的提示: 异常详细信息: System.InvalidOperatio ...
- 不要在构造和析构函数中调用虚函数
构造函数中不能有虚函数的原因: 原因一:基类构造期间虚函数不会下降到派生类阶段,也就是本身我们声明一个派生类对象,它应该先去调用基类的构造,若此时基类构造里面有虚函数,则这个虚函数是基类的虚函数,而不 ...
最新文章
- 【转】用例结构优化心得
- 上传文件大小限制,webconfig和IIS配置大文件上传
- Android之稍微靠谱点的透明Activity(不获取触摸事件)
- 论文浅尝 | 基于深度强化学习的远程监督数据集的降噪
- 语言做一个自动售货机软件_软件开发手机app系统软件高端定制做一个app软件要多少钱...
- 解决Numpy 报错 ValueError: zero-size array to reduction operation maximum which has no identity
- Java注解之自定义注解
- 世界各国简称 电话区号JSON数据
- 云计算平台的市场现状和云计算平台的核心价值是什么?
- 华为快应用-怎么使用卡片功能
- SaaSpace:最好的免费网络安全工具
- lisp方格网法计算土方量_CAD计算土方方量插件
- python画一个心形照片墙怎么摆_这个七夕节,用Python为女友绘制一张爱心照片墙吧!...
- 韩寒诉百度文库侵权案分析
- STC12C5A60S2输出时钟频率
- 2012人类将从“微博体”过渡到“微媒体”。至于你信不信,反正我信了
- selenium自动化测试--126邮箱登录问题总结
- 毫米波电路的PCB设计和加工(第一部分)
- 计算机网络与技术课本,高等学校计算机科学与技术教材:计算机网络基础教程...
- 网龙前员工:解读百度收购91无线的内幕
热门文章
- 计算机网络解决数据包丢失,数据包丢失时网络控制系统的稳定性分析及设计
- PSAM卡---中国人民银行PSAM卡管理规范.doc
- Content-Type一览
- linux火狐浏览器49.0安装教程,firefox for linux
- 微信小程序 没有找到可以构建的npm包
- 单链表反转的原理和python代码实现
- loj 300 [CTSC2017]吉夫特 【Lucas定理 + 子集dp】
- 多个工作表同时处理+选中不连续的单元格和工作表
- 【MySQL】玩转定时器
- POJ 2785 4 Values whose Sum is 0