C++拾遗--虚函数表
来源:互联网 发布:淘宝图片如何加护盾 编辑:程序博客网 时间:2024/05/21 09:20
C++拾遗--虚函数表
前言
C++的多态依赖虚函数来实现。若类存在虚函数,则每一个类的实例都维护了一个地址,这个地址指向虚函数表。虚函数表中存放的是类中所有虚函数的地址。下面我们找出虚函数表的地址,从而获得每个虚函数的地址,然后使用地址直接调用虚函数。
正文
1.空类的size
#include <iostream>using namespace std;class MyClass{};int main(){cout << "sizeof(MyClass) = " << sizeof(MyClass) << endl;cin.get();return 0;}运行
空类没有定义任何的成员,这样的类size都是1,1表示该类存在。
2.有函数(非虚函数)成员的类
#include <iostream>using namespace std;class MyClass{void fun(){};};int main(){cout << " sizeof(MyClass) = "<< sizeof(MyClass) << endl;cin.get();return 0;}运行
这样的类:无数据成员,只有非虚的函数成员,它的size都是1。原因:代码区不计入size、
3.只含有虚函数的类
#include <iostream>using namespace std;class MyClass{virtual void fun(){};};int main(){cout << " sizeof(MyClass) = "<< sizeof(MyClass) << endl;cin.get();return 0;}运行
这个4即是指向虚函数表指针的大小。
4.虚函数表
在VC下,无论该类是否有数据成员,指向虚函数表的指针(vptl),都位于对象的首地址处。
#include <iostream>using namespace std;class MyClass{public:virtual void fun1(){cout << "void fun1()" << endl;}virtual void fun2(){cout << "void fun2()" << endl;}virtual void fun3(){cout << "void fun3()" << endl;}};//Fun是函数指针typedef void(*Fun)();int main(){cout << "******虚函数原理***by David***" << endl;MyClass *p = new MyClass;cout << "虚函数表的地址" << ends;cout << (void*)*(int*)p << endl;Fun pfun1 = (Fun)*(int*)(*(int*)p);cout << (void*)pfun1 << ends;pfun1();Fun pfun2 = (Fun)*((int*)(*(int*)p) + 1);cout << (void*)pfun2 << ends;pfun2();Fun pfun3 = (Fun)*((int*)(*(int*)p) + 2);cout << (void*)pfun3 << ends;pfun3();//断点cin.get();return 0;}
运行
在调试窗口中可看到相关局部变量和虚函数表的相关信息
下面来详细分析下,我们是如何获得虚函数表的地址的
联合上图,我们来一步一步推导出虚函数表的地址以及各个虚函数的地址
1.指针p的类型是MyClass *
2.虚函数表的地址在对象的首部(前四个字节),*p的类型是MyClass,为了获取前四个字节的存储内容,必须对p进行类型转换->(int*)p
3.如是*(int*)p就是虚函数表的地址,之所以加上void*,因为这是C++中对指针的标准打印方式。
4.虚函数表的地址*(int*)p,指向虚函数表的首部。每个虚函数的地址都是四个字节大小的,也就是说,虚函数表的前四个字节的存储内容就是第一个虚函数fun1的地址。随后四个字节的存储内容是第二个虚函数fun2的地址,以此类推……
5.为了获取fun1的地址,同理需要对*(int*)p进行类型转换->(int*)(*(int*)p),需要指出此时*(int*)p的类型是int*,解引用后就是fun1的地址了 *(int*)(*(int*)p)
6.如何获取fun2的地址呢,那当然就是对上一步的指针(int*)(*(int*)p)进行移动,移动4个字节 (int*)(*(int*)p)+1,解引用后*((int*)(*(int*)p)+1),就是fun2的地址。再次移动四个字节 (int*)(*(int*)p)+2,解引用后*((int*)(*(int*)p)+2),就是fun3的地址。
本专栏目录
- C++拾遗 目录
- CCPP Blog 目录
- C语言函数拾遗
- C++拾遗--虚函数表
- C/C++拾遗——main函数
- C 拾遗
- c拾遗
- 【C++拾遗】 C++虚函数实现原理
- C拾遗(三)函数式宏定义
- C++拾遗--函数模板
- C++拾遗--函数重载
- 构造函数拾遗
- 学习拾遗--range函数
- C/C++拾遗
- C语言拾遗
- c语言拾遗3
- c语言拾遗4
- C语言拾遗
- C/C++ 拾遗(1)
- C语言拾遗
- (三十七)从私人通讯录引出的细节I -Notification -Segue -HUD -延时
- Linux下解压rar文件
- Kafka安装与配置
- UISearchDisplayController 和 UISearchBar
- Linux时间子系统之六:高精度定时器(HRTIMER)的原理和实现
- C++拾遗--虚函数表
- 百度面试题
- ubuntu下SVN安装与使用
- springmvc简单实现权限控制
- ARM映像文件
- KAFKA安装和使用
- iOS 简单的loading弹出框实现
- java图片压缩
- SSM框架——详细整合教程(Spring+SpringMVC+MyBatis)