当虚函数遇上构造函数、析构函数

在C++中,构造函数析构函数被用来执行特殊的任务。那么,当它们遇上虚函数这个更为复杂的概念时,事情会是怎样的呢,编译器会如何处理?我们先做试验,然后再进行分析。


首先是在构造函数中调用虚成员函数:

#include <iostream>

class Base
{
public:
	Base()
	{
		std::cout<<"Base::Base()."<<std::endl;
		VFunc();
	}

	virtual void VFunc()
	{
		std::cout<<"Base::VFunc()."<<std::endl;
	}
};

class Derived : public Base
{
public:
	Derived()
	{
	}

	virtual void VFunc()
	{
		std::cout<<"Derived::VFunc()."<<std::endl;
	}
};

int main(int argc, char * argv[])
{
	Base *pBase = new Derived;
	delete pBase;

	return 0;
}

运行结果:

很明显,在构造函数中调用的虚函数,并没有产生通常的虚函数调用效果。

分析:假如在父类构造函数中,实现通常的虚函数调用效果——调用子类中重定义的虚函数,而此时,子类对象尚未构造出来,其对应虚函数的行为——比如访问成员变量,既是无意义的,更是不安全的!为什么说不安全呢,因为在子类的虚函数中,去访问一个指针类的成员变量——此时变量值是随机的,将产生不可预期的结果。


然后再试试在析构函数中调用虚成员函数:

#include <iostream>

class Base
{
public:
	virtual void VFunc()
	{
		std::cout<<"Base::VFunc()."<<std::endl;
	}

	virtual ~Base()
	{
		std::cout<<"Base::~Base()."<<std::endl;
		VFunc();
	}
};

class Derived : public Base
{
public:	
	virtual void VFunc()
	{
		std::cout<<"Derived::VFunc()."<<std::endl;
	}

	~Derived()
	{
		std::cout<<"Derived::~Derived()."<<std::endl;
	}
};

int main(int argc, char * argv[])
{
	Base *pBase = new Derived;
	delete pBase;
	
	return 0;
}
运行结果:


可以看出,在析构函数中调用虚成员函数,其效果和在构造函数中类似。

同样的道理,当父类中的析构函数被调用时,子类的析构函数已经调用完毕——子类中的成员已经被销毁。此时,如果父类中的虚函数调用作用到子类对象之上,那么其行为也将是无意义不安全的。


实际上,编译器在碰到构造函数、析构函数中的虚成员函数调用时,不会采用虚函数的机制——运行时绑定,而是直接执行早期绑定,定向到该虚函数的‘本地版本’。我们在编码实践中应注意到这一点。


==============================End===============================


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值