《Effective C++》条款9:不在构造和析构函数中调用virtual函数
本章主要讲解了多态情况下在构造函数内调用virtual的问题;
针对于多态情况下,我们希望根据指针指向的类型调用不同的虚函数,但是在构造函数中可能存在问题;
例如下列例子:
class Transaction {
public:
	Transaction();
	virtual void logTransaction() const = 0;//pure virtual函数;
};
Transaction::Transaction() {
	//...
	logTransaction();
}
class BuyTransaction :public Transaction {
public:
	virtual void logTransaction() const;
};
按照多态性定义,如果我们对子类BuyTransaction进行构建:
BuyTransaction bt;
根据构造函数调用链,首先先调用Transaction函数,由于构造函数内调用二零虚函数logTransaction(),按照多态定义,应该调用bt的logTransaction(),但是实际并不如此;
实际调用的还是基类的logTransation()函数;
主要原因如下:
1.在实际构造和析构阶段,所有virtual函数都是视为非虚函数;
2.在基类部分构造和析构阶段,派生类仍然是视之为基类,并不当作派生类来使用;
所以,如果在构造和析构中使用虚函数并不能达到多态行为,所以应该避免这种行为;
值得注意的是:通过函数嵌套调用间接调用虚函数仍然存在这种预期之外的错误,唯一的区别是编译器无法显式的检查出来;
class Transaction {
public:
	Transaction();
	virtual void logTransaction() const = 0;//pure virtual函数;
private:
	void init() {
		logTransaction();
	}
};
Transaction::Transaction() {
	//...
	init();
}
如上所示,编译器无法检查出析构和构造函数中虚函数的嵌套调用,实际调用结果和之前的一样;
所以总而言之:构造和析构期间不要调用virtual函数,因为此类调用从不下降到derived class层面;
class Transaction {
public:
	explicit Transaction(const std::string& logInfo);
	void logTransaction(const std::string& logInfo) const;//pure virtual函数;
private:
};
Transaction::Transaction(const std::string& logInfo) {
	logTransaction(logInfo);
}
class BuyTransaction :public Transaction {
public:
	BuyTransaction(const std::string& parameters):Transaction(createLogString(parameters)) {
		//do something;
	}
private:
	static std::string createLogString(const std::string& parameters);
};
该方法具有一定的技巧性:
首先将虚函数变成基类普通函数,根据输入参数值进行构造;
派生类根据自己的类型传入不同的parameters来通过createLogString构建出不同的参数值,传入基类构造函数,基类构造函数调用log函数,来达到不同的类具有不同的信息输出,从而达到多态的同等作用;
骚操作,需要细细体会一下;

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号