《Effect C++》学习------条款09:绝不在构造和析构过程中调用virtual函数
来源:互联网 发布:windows phone 输入法 编辑:程序博客网 时间:2024/04/30 23:18
不该在构造函数和析构函数期间调用virtual函数,这一点是C++与jave/C#不同的地方之一。
假设有一个class继承体系,用来模拟股市交易如买进、卖出的订单等等。这样的交易一定要经过审计,所以每当创建一个交易对象,在审计日志中也需要创建一笔适当记录。下面是颇为合理的做法:
class Transaction // 交易的基类{public: Transaction(); virtual void logTransaction() const = 0; // 用于记录交易日志};Transaction::Transaction(){ logTransaction(); // 调用虚函数}class BuyTransaction : public Transaction // 买进股票{ virtual void logTransaction() const;};void BuyTransaction::logTransaction() const{ }class SellTransaction : public Transaction // 卖出股票{ virtual void logTransaction() const;};void SellTransaction::logTransaction() const{ }int main(){BuyTransaction b;return 0;}```
上述代码中执行BuyTransaction b时,会调用基类的构造函数,而基类的构造函数会调用一个虚函数来完成工作。但是该虚函数是否会调用派生类的对应函数呢?答案是否定的,解释如下:
1> 基类的构造是先于派生类的构造的。当基类的构造函数执行时,派生类中的成员尚未被初始化,如果允许基类构造期间调用派生类的函数,可能也会调用了没有初始化的“垃圾值”,导致不确定行为发生。
2> 基类构造期间,virtual函数的行为绝对不会伸到派生类中,因为此时构造的是基类,即此时构造的对象的类型是基类而非派生类,这点很重要。
在基类构造期间,虚函数不是虚函数
但是有时我们在构造基类的时候又需要派生类中才有的参数信息,如何解决:
在基类中将logTransaction函数改为非虚函数,然后在构造派生类时将必要的参数传递到基类的构造函数中去,像如下这样:
#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{ }class BuyTransaction : public Transaction // 买进股票{public: BuyTransaction(const std::string& parameter) : Transaction(parameter){ }};int main(){ BuyTransaction b("BT"); return 0;}
由上可知,如果基类构造时要使用派生类的信息,可以通过派生类构造函数的初始化列表传入相关参数,切不可调妄图调用虚函数实现,因为在构造基类期间其对象的类型是基类类型。
对于析构函数也是同样的道理,基类的析构总是在派生类析构后才进行,此时派生类的对象已经不存在了,而调用虚函数必然会引发一个不确定行为。当然你也可以将基类的虚函数实现后在析构函数中进行调用,但是这样的话,为什么不定义为非虚函数呢,虚函数的意义将不复存在了。
请记住:
- [x] 在构造和析构期间不要调用virtual函数,因为这类调用从不下降至派生类(比起当前执行构造函数和析构函数的那层)。
- 《Effect C++》学习------条款09:绝不在构造和析构过程中调用virtual函数
- Effective C++:条款09:绝不在构造和析构过程中调用virtual函数
- 读书笔记《Effective C++》条款09:绝不在构造和析构过程中调用virtual函数
- 【Effective c++】条款09:绝不再构造和析构过程中调用virtual函数
- 条款09:绝不在构造和析构过程中调用virtual函数
- 条款09:绝不在构造和析构过程中调用virtual函数
- 条款09:绝不在构造和析构过程中调用virtual函数
- Effective C++ 读书笔记 条款09:绝不在构造和析构过程中调用virtual函数
- 条款09 绝不在构造和析构过程中调用virtual函数
- 条款09:绝不在构造和析构过程中调用virtual函数
- 条款09 绝不在构造和析构过程中调用 virtual 函数
- 条款09:绝不在析构和构造过程中调用virtual函数
- 条款09:绝不在构造和析构过程中调用virtual 函数
- 条款09:绝不在构造和析构过程中调用virtual函数
- 条款09:绝不在构造和析构过程中调用virtual函数
- 条款09:绝不在构造和析构过程中调用virtual函数
- Effective c++学习笔记——条款09:绝不在构造和析构过程中调用virtual函数
- Effective c++学习笔记——条款09:绝不在构造和析构过程中调用virtual函数
- RBF神经网络通用函数 newrb, newrbe
- 地址传参
- git知识点(持续更新中)
- JAVA基础笔记(十五)反射
- 正则表达式的相关前端题目
- 《Effect C++》学习------条款09:绝不在构造和析构过程中调用virtual函数
- JAVA基础笔记(十六)JDBC
- 【斯坦纳树】【LA5717】Beijing 2011 Peach Blossom Spring解题报告
- 理解和正确使用Java中的断言
- leetcode Submission Details
- HBase查看表大小
- ButterKnife的使用
- 第二周 项目2 程序的多文件组织
- 《Effect C++》学习------条款10:令 operator= 返回一个 reference to *this