不要在构造和析构函数中调用虚函数
程序员文章站
2024-03-21 11:01:22
...
注:本文对应Effective C++ 条款9
基类是一个模拟股票交易的类,成员函数logTransaction()是记录每一笔交易,具体买/卖派生类实现自己的记录函数。
基类的构造函数中调用了这个虚函数。
先来思考下面这段代码:
#include<iostream>
using namespace std;
//交易类
class Transaction
{
public:
Transaction()
{
logTransaction();
}
//记录每一笔买/卖记录
virtual void logTransaction() const = 0;
};
//买进类
class BuyTransaction :public Transaction
{
public:
virtual void logTransaction()const
{
cout << "BuyTransaction::logTransaction()" << endl;
}
};
//卖出类
class SellTransaction :public Transaction
{
public:
virtual void logTransaction()const
{
cout << "SellTransaction::logTransaction()" << endl;
}
};
int main()
{
BuyTransaction b;
return 0;
}
下面是VS下的运行实例:
下面是linux下的运行实例:
都是直接被编译器拒绝了。
思考为什么?有什么错误吗?
当构造派生类对象构造时,先调用基类的构造函数,而在基类的构造函数中,调用了虚函数,这时候调用的是基类的logTransaction()函数,并不是派生类自己实现的logTransaction()函数。
换句话说,即使当前要建立的对象是派生类对象,但是基类构造函数期间,虚函数不会下降到派生类的层面,因为基类构造期间虚函数不是虚函数。
换种容易理解的方式,基类构造函数先于派生类构造函数执行,当基类构造函数执行时,派生类的成员变量尚未初始化,如果此时调用虚函数,并且下降至派生类层面,因为派生类的函数必然取用了自己的成员变量,但是此时它的成员变量还没有被初始化,这是一个通向未知错误的道路,所以C++阻止了你走这条路。
析构函数亦然,一旦派生类的析构函数开始执行,对象内的派生类成员就是未定义的,如果这时再进入基类的析构函数中,调用的虚函数必然是基类的,因为派生类已经不是一个完整的类型了。
综上所述,请不要在构造和析构函数中调用虚函数,大多数的编译器也都阻止了这个行为。
下一篇: 如何数据表(SQL Server)的创建