虚函数表的打印

来源:互联网 发布:c 动漫网站源码 编辑:程序博客网 时间:2024/06/05 09:26

虚函数表的打印

在进行打印虚函数表之前,有几个需要了解和掌握的知识点:

一. typedef 的使用

     在现实生活中,信息的概念可能是长度、数量和面积等。而在计算机语言中,数据被简化成了一些基本的数据类型,如int、float、

double等。从数据的基本类型上,我们不能看出其代表的物理属性。为了使基本的数据类型具有其可知的物理属性,C语言中引入了

类型重定义语句typedef,可以为基本数据类型定义新的类型名称,从而反映数据的物理属性。

用法:typedef   基本类型名称   类型标识符

例:   typedef   int  area;   // 重定义aera为int的类型标识符。

           int a; 

           area b; // 在类型重定义后,类型标识符可以像基本数据类型那样定义变量。

类型重定义语句 typedef 的基本用法

(1)为基本数据类型定义新的类型标识符。

typedef int Length;int a;Length b;

(2)为自定义数据类型(结构体、共用体和枚举类型)定义简洁的类型标识符。

若用普通方法定义结构体类型:

struct student{int age;char name;char sex;};struct student obj1;

在用结构体类型定义变量时,在变量名前都要加上保留字struct,而不能直接用类型名直接定义变量。

为了简化结构体变量的定义(直接用结构体类型名定义结构体变量),我们使用重定义语句typedef进行类型定义:

typedef struct student{int age;char name;char sex;};student obj1;

(3)为数组定义简洁的类型名称。

在C++中,可以将具有一定长度的数组看成一个新的数据类型,并能用重定义语句typedef对其进行标识符的重定义。

普通定义: int a[10];

用重定义语句定义数组: typedef int array[10];

                                        array a,b,c;  // 定义三个长度为10的整型数组a、b、c。

(4)为指针定义简洁的名称。

 <1>  为数据指针定义简洁的名称。

         typedef  char * string;

         string name={“wangxiaoya”};

 <2>  为函数指针定义新的名称。

         typedef int (*MyFun) (int a,int b);


二. 函数指针和指针函数

指针函数:返回值为地址的函数。如 int * Fun(int a,int b);

函数指针:函数名为一个指针。

                  与数组进行相近的理解,数组名代表数组第一个元素的地址,即数组名代表数组的首地址。同理,对于函数指针来说,函数

                  名为指向函数第一条指令的常量指针。

                  编译器在对函数进行编译时,为每一个函数分配一个首地址,存放函数的第一条指令。一般的,我们用一个指针来存放函数的

                  首地址,即函数指针,所以也称函数指针势函数的别名,故可以用函数指针来调用函数的内容。

                  如 int (*Fun) (int a,int b);


有了上述知识的铺垫,我们进行虚函数表的打印

#include<iostream>using namespace std;#include<Windows.h>class Base  {public:virtual void func1(){cout << "Base::func1" << endl;}virtual void func2(){cout << "Base::func2" << endl;}private:int a;};class Derive :public Base{public:virtual void func1(){cout << "Derive::func1" << endl;}virtual void func3(){cout << "Derive::func3" << endl;}virtual void func4(){cout << "Derive::func4" << endl;}private:int b;};                                                                                                                              typedef void(*FUNC)(void);void PrintVTable(int* VTable){cout << " 虚表地址" << VTable << endl;for (int i = 0; VTable[i] != 0; ++i){printf(" 第%d个虚函数地址 :0X%x,->", i, VTable[i]);FUNC f = (FUNC)VTable[i];f();}cout << endl;}int main(){Derive d1;PrintVTable((int*)(*(int*)(&d1)));system("pause");return 0;}

运行结果:

首先,我们要知道虚函数表在内存中的存储形式

在C++中,多态性是通过虚函数实现的,而虚函数的实现依靠虚函数表的存在。实现多态性的基本操作是将基类的对象指针指向子类对象,

通过子类对象调用函数。虚函数表中存放着重写后的虚函数。虚函数表如同一个地图,指明了实际所应该调用的函数。

C++中有规定,编译器必需要保证虚函数表的指针存在于对象实例中最前面的位置(为了保证正确取到虚函数的偏移量)。 这意味着我们

通过对象实例的地址得到这张虚函数表,然后就可以遍历其中函数指针,并调用相应的函数。

为了打印出这张虚函数表,我们把内存中的虚函数表看做一个整型数组,数组元素就是虚函数,为了取出虚函数的地址进行强制类型转换。

核心代码:

typedef void(*FUNC)(void);  //重定义函数指针名为FUNCvoid PrintVTable(int* VTable)  //把虚函数表当做一个数组传入{cout << " 虚表地址" << VTable << endl;  //数组名就是函数的首地址,即虚函数表的首地址for (int i = 0; VTable[i] != 0; ++i)  //虚函数表的末尾元素是0,通过循环控制打印次数{printf(" 第%d个虚函数地址 :0X%x,->", i, VTable[i]);FUNC f = (FUNC)VTable[i];  f();}cout << endl;}