关于C++虚函数与普通函数的编译与调用机制
2014-03-04 23:33
330 查看
本文转自:http://www.cnblogs.com/huhuuu/p/3463109.html
----------------------------------------------------------------------------------------
引出:写个类A,声明类A指针指向NULL,调用类A的方法会有什么后果,编译通过吗,运行会通过吗?
(在VS2008与VC++的情况下) 有错误欢迎批评指正!
看到这个的时候,一定以为运行会报错吧。
但是奇迹般的,编译器输出了:base fun
在看这个代码,还以为会输出base fun么,又错了,运行报错!
为什么会是这个结果?
可以发现,一个是虚函数,一个普通函数
在观察下内存中得情况:
发现果然虚函数还没在内存中,而fun2已经在内存中了
在看看汇编:
明显发现虚函数的调用比普通函数多了好几个步骤,
ecx 中放的this 指针,所以this=0(NULL),但是普通函数fun2放在全局内存区,所以可以访问
而虚函数是根据虚函数表寻找的,这时没有虚函数表,自然就没法查到虚函数的地址了
感谢 hoodlum1980 更详细的说明:因为非虚函数的地址对编译期来说“静态”的,也就是函数地址在编译期就已经确定了,实例地址对于非虚函数只是那个 this 指针参数。所以只要不访问类的实例数据就没什么问题。而虚函数的地址,是先到实例的地址前面去查找它的虚函数表所在的地址。然后从虚函数表里取出该函数所对应的元素(虚函数表是一个函数指针数组)来call的。(当然一个已知的类的虚函数表的内容也是编译期静态的,但不同类的虚函数表内容不同,即运行时多态的基础)所以实例如果为NULL,是个有特殊意义的值,是会触发运行时错误的。
总结:类中的虚函数是动态生成的,由虚函数表的指向进行访问,不为类的对象分配内存,就没有虚函数表就无法访问。
类中的普通函数静态生成,不为类的对象分配内存也可访问。
----------------------------------------------------------------------------------------
引出:写个类A,声明类A指针指向NULL,调用类A的方法会有什么后果,编译通过吗,运行会通过吗?
(在VS2008与VC++的情况下) 有错误欢迎批评指正!
#include<stdio.h> #include<iostream> using namespace std; class base{ int a; public: void fun(){ printf("base fun\n"); } }; int main(){ base *b=NULL; b->fun(); }
看到这个的时候,一定以为运行会报错吧。
但是奇迹般的,编译器输出了:base fun
#include<stdio.h> #include<iostream> using namespace std; class base{ int a; public: virtual void fun(){ printf("base fun\n"); } }; int main(){ base *b=NULL; b->fun(); }
在看这个代码,还以为会输出base fun么,又错了,运行报错!
为什么会是这个结果?
#include<stdio.h> #include<iostream> using namespace std; class base{ int a; public: virtual void fun(){ printf("base fun\n"); } void fun2(){ printf("base fun\n"); } }; int main(){ base *b=NULL; b->fun(); b->fun2(); }
可以发现,一个是虚函数,一个普通函数
在观察下内存中得情况:
发现果然虚函数还没在内存中,而fun2已经在内存中了
在看看汇编:
明显发现虚函数的调用比普通函数多了好几个步骤,
ecx 中放的this 指针,所以this=0(NULL),但是普通函数fun2放在全局内存区,所以可以访问
而虚函数是根据虚函数表寻找的,这时没有虚函数表,自然就没法查到虚函数的地址了
感谢 hoodlum1980 更详细的说明:因为非虚函数的地址对编译期来说“静态”的,也就是函数地址在编译期就已经确定了,实例地址对于非虚函数只是那个 this 指针参数。所以只要不访问类的实例数据就没什么问题。而虚函数的地址,是先到实例的地址前面去查找它的虚函数表所在的地址。然后从虚函数表里取出该函数所对应的元素(虚函数表是一个函数指针数组)来call的。(当然一个已知的类的虚函数表的内容也是编译期静态的,但不同类的虚函数表内容不同,即运行时多态的基础)所以实例如果为NULL,是个有特殊意义的值,是会触发运行时错误的。
总结:类中的虚函数是动态生成的,由虚函数表的指向进行访问,不为类的对象分配内存,就没有虚函数表就无法访问。
类中的普通函数静态生成,不为类的对象分配内存也可访问。
相关文章推荐
- C++继承类和基类之间成员函数和虚函数调用机制
- C++ 普通函数和虚函数调用的区别
- C++继承类和基类之间成员函数和虚函数调用机制
- C++编译期间的虚函数调用机制 .
- C++中virtual(虚函数)和普通函数调用的不同
- C++ 普通函数和虚函数调用的区别
- C++继承类和基类之间成员函数和虚函数调用机制
- C++编译期间的虚函数调用机制
- linux下C与C++混合编译、C++调用C、C++使用C中的函数
- c++ 普通函数 虚函数 纯虚函数 代码例子
- 在C++ 程序中调用被 C编译器编译后的函数,为什么要加 extern “C”声明?
- 关于对话框的知识(函数的调用机制和控件的使用)
- [转]浅析C++中虚函数的调用及对象的内部布局(利用汇编深刻理解C++虚函数底层实现机制)
- 转载-关于C语言中函数调用和参数传递机制的探讨
- 在C++中调用被C编译器编译后的函数,为什么要加extern "C"
- C/C++拾遗录--查看关于_declspec(naked)与普通的函数在寄存器变化方面的不同点
- C/C++ 函数的编译方式与调用约定以及extern “C”的使用
- Why? 在C++中调用被C编译后的函数,要在声明的前面加extern "C"
- VC6.0配置LUA编译环境及LUA调用C++函数的简单示例
- 初始化函数中的虚函数调用( C++ vs python )