您的位置:首页 > 编程语言 > C语言/C++

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

2013-01-26 22:54 337 查看
问题:

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

#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().
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: