从一道题分析C++虚函数机制

问题:

写出下面程序的运行结果:

#include <iostream>
using std::cout;
using std::endl;

class A
{
public:
	void nonVirtualFun()
	{
		cout<<"1"<<endl;
	}
	virtual void virtualFun()
	{
		cout<<"2"<<endl;
	}
	virtual ~A(){}
};
class B:public A
{
public:
	void nonVirtualFun()
	{
		cout<<"3"<<endl;
	}
	void virtualFun()
	{
		cout<<"4"<<endl;
	}
};
int main()
{
	A a;
	B b;
	A *pa=&a;
	pa->nonVirtualFun();
	pa->virtualFun();

	pa=&b;
	pa->nonVirtualFun();
	pa->virtualFun();

	B *pb=(B*)(&a);
	pb->nonVirtualFun();
	pb->virtualFun();
	return 0;
}

如果你的答案是1,2,1,4,3,2

那么恭喜你答对了。下面来分析一下内存与虚函数机制。

首先要明确的是:

对于类的非虚函数,那么编译之后与全局函数没有什么区别,编译器会自动给该函数加一个this参数,用于指明是哪个对象调用的该函数。

对于类的虚函数,都是通过虚函数指针(vptr-->vtbl)来访问的。

所以编译之后的类A和类B的内存模型如下:


这也可以解释大多数人认为C++比C慢的原因:对于虚函数的访问需要简直通过指针,如果你不用虚函数,C++并不比C慢。

从下面这段代码开始分析:

	pa=&b;
	pa->nonVirtualFun();
	pa->virtualFun();


A*类型指针pa实际指向一个B类,对于编译器来说他看到的pa就是指向基类的,所以访问非虚函数时,把子类对象b的地址当作this传递给A::nonVirtualFun()。

访问虚函数时通过虚函数表(vtbl),由于vptr指向的是子类的虚函数表,所以自然而然的访问了子类B::virtualFun(),即实现了运行期多态。

再来分析最后一段代码:

	B *pb=(B*)(&a);
	pb->nonVirtualFun();
	pb->virtualFun();


子类指针pb指向了一个基类对象,调用非虚函数时,把基类对象地址以this传递给B::nonVirtualFun()。当访问虚函数时,由于实际指向的是个基类,所以通过虚函数表访问时,自然查找到A::virtualFun().


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值