IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> Effective C++ Item 09: 绝不在构造和析构过程中调用virtual函数 -> 正文阅读

[C++知识库]Effective C++ Item 09: 绝不在构造和析构过程中调用virtual函数

开始

有一个class继承体系,用来模拟股市交易, 比如买进, 卖出的订单。交易是需要审计的,我们每创建一个交易对象, 就需要在审计日志中创建一个记录,示例如下:

class Transaction
{
public:
	Transaction();
	virtual void logTransaction() const = 0;
	...
};

Transaction::Transaction()
{
   ...
   logTransaction();
}

class BuyTransaction: public Transaction 
{
public:
	virtual void logTransaction() const;
	...
};

class SellTransaction : public Transaction
{
public:
	virtual void logTransaction() const;
};	

我们开始执行

BuyTransaction b;

会有一个BuyTransaction的构造函数被调用, 而Transaction的构造函数会在其之前被调用, 在这个构造函数中, logTransaction会被调用, 而问题在于这个时候被调用的并不是子类的函数, 而是基类的函数, 也就是说在构造函数的期间, virtual函数并不会下降到子类的函数,我们可以说:在base class的构造期间,virtual函数并不是virtual函数。

相同的道理同样作用于析构函数, 一旦子类的析构函数开始执行, 子类的成员变量就会进入未定义的的状态,可以说进入析构函数的子类对象就成为了一个基类对象。

侦测构造函数或者析构函数中是否调用了virtual函数,需要一定的手段, 如果Transaction有多个构造函数,每一个都需要执行相同的动作,那么避免代码重复的一个优秀做法是把共同的初始化代码放进一个初始化函数内:

class Transaction
{
public:
	Transaction()
	{
		init();
	}
	virtual void logTransaction() const = 0;
	...
private:
	void init()
	{
		...
		logTransaction(); 
	}
};

这样的函数回逃避掉编译器的检查,在执行中会导致一个错误的产生,而如果logTransaction不是纯虚函数的话,运行会没有任何问题, 而检查错误行为会很难,所以我们要保证在构造函数和析构函数期间, 没有virtual被调用。

如果我们一定要在构造的过程中调用适当版本的logTransaction函数, 我们可以考虑将logTransaction改成非虚的函数, 然后子类需要传递必要的信息:

class Transaction
{
public:
	explicit Transaction(const std::string logInfo);
	void logTransaction(const std::string logInfo) const;
	...
};

Transaction::Transaction(const std::string logInfo)
{
   ...
   logTransaction(logInfo);
}

class BuyTransaction: public Transaction 
{
public:
	BuyTransaction(parameters)
	: Transaction(createLogString (parameters))
	{ ... }
	...
private:
	static std::string createLogString(parameters);
};
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-10-18 17:12:27  更:2021-10-18 17:12:40 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 3:33:26-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码