从一道题分析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().
写出下面程序的运行结果:
#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().
相关文章推荐
- C++异常机制的实现方式和开销分析(作者:白杨)
- C++基于虚函数的多态分析
- C++ 中的异常机制分析
- c++ 虚函数机制 效率问题
- 从一个微型例子看“C/C++的内存分配机制”和“数组变量名与指针变量名”(转)
- c++ 虚函数的实现机制:笔记
- C++ 异常机制分析
- C++异常机制的实现方式和开销分析
- 【反汇编分析】C++成员函数和虚函数
- c++ 虚函数的实现机制
- C++ 虚函数机制-(转载)
- [转]C++异常机制的实现方式和开销分析
- C++异常机制的实现方式和开销分析
- C++ 异常机制分析
- 转 C++异常机制的实现方式和开销分析 白杨 http://baiy.cn
- C++面向对象特性实现机制的初步分析 Part1
- C++对象模型Data语意学分析、虚继承底层实现机制
- C++异常机制的实现方式和开销分析 (大图,编译器会为每个函数增加EHDL结构,组成一个单向链表,非常著名的“内存访问违例”出错对话框就是该机制的一种体现)
- C/C++—— C++中构造函数不能是虚函数的原因分析
- C++虚函数的实现机制