本文主要是介绍绝不在构造和析构过程中调用虚函数,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
一、中心内容
因为类调用从不下降至派生类,导致若为纯虚函数,则找不到函数的实现代码;若为非虚函数,则可能会导致调用错误的函数版本。。。
二、内容简介
考虑这样一系列继承:
class Transaction{
public:
Transaction();
virtual void logTransaction() const = 0;//每创建一个交易对象,在审计日志中需要创建一笔适当记录,由此函数实现
......
};
Transaction::Transaction()
{
......
logTranction();
}
class BuyTranction: public Transaction{
public:
virtual void logTransaction() const;
......
};
class SellTranction : public Transaction{
public:
virtual void logTransaction() const;
......
};
note:
执行语句:BuyTransaction b; 时发生的事情:
(1)派生对象内的基类成分会在派生自身成分被构造之前先构造妥当;
(2)红色语句被调用的是Transaction内的版本,不是BuyTransaction的版本!!!!!!
(3)即,在基类构造期间, 虚函数不是虚函数,不会下降到派生类阶层。
(4)或者说,派生类的基类部分构造期间,对象的类型是基类而不是派生类!!!!!!
具体原因:
因为基类构造函数执行时,派生类的成员变量尚未初始化,若下降到派生阶层,必然会用到局部成员变量,但是这些变量尚未初始化,会出现错误。
针对红色语句部分,基类构造函数调用了虚函数,这是不被允许的,具体原因:
1、纯虚函数
由于一般情况下,纯虚函数在基类中是不做定义的,所以调用的时候会找不到函数的定义代码,不管是基类构造函数还是派生类构造函数构造基类成分时;
2、非纯虚函数
原本构造一个派生类对象需要调用的是派生类版本的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);
};
note:
1、红色部分就是派生类为基类构造函数提供的必要的logTransaction信息;
2、绿色部分的私有成员之所以定义为静态成员,在于静态成员函数不包含this指针,这样就不会指向其他尚未初始化的成员变量,避免了构造基类成分是出现错误。
note:
最重要的是!!!
因为使用非纯虚函数会使得在构造派生对象时,创建基类成分过程中,调用基类版本的虚函数导致错误,不能实现向下调用!!!
所以,在派生类中创建这么一个私有静态函数,增加可读性,因为是static又不会包含this指针指向派生类中未初始化的成员变量,向上传递因类而异的不同的构造信息给基类成分的构造函数,这样就不会调用错虚函数。。
这篇关于绝不在构造和析构过程中调用虚函数的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!