#include <iostream>
#include <stdio.h>
using namespace std;
//定义两个函数指针类型
typedef void(*pFunc)(void);
typedef int(*pSum)(int,int);
//定义测试基类
class A
{
public:
//定义虚函数func
virtual void func()
{
printf("test============\n");
}
private:
//定义私有的虚函数sum(用于测试)
virtual int sum(int x,int b)
{
printf("func sum==========%d %d\n",x,b);
return x + b;
}
};
//定义测试子类
class B :public A
{
public:
//定义虚函数func()用于覆盖基类中的func
void func()
{
printf("test class B =============\n");
}
//定义虚函数tool用于测试
virtual void tool()
{
printf("class b============\n");
}
};
int main()
{
//使用子类构建指向子类的对象指针
A *a = new B;
//获取虚函数表中的第一个函数指针
pFunc func = (pFunc)*(int *)*(int *)a;
//输出
func(); //子类中的func
//通过虚函数表访问基类中的私有虚函数(也适用于:子类构造的对象通过虚函数表访问基类的私有函数)
//获取虚函数表中的第二个函数指针 //基类中的私有函数(sum函数)
pSum sum = (pSum)*((int *)*(int *)a+1);
int x = 10;int b = 2000;
//传递参数,并输出, //注意能够输出测试字符串,但是传递的参数被迫坏掉,无法正常运算
cout << sum(x,b)<<endl;;
//使用对象指针调用sum-------:无法访问
//cout << a -> sum(x,b)<<endl;
//获取虚函数表中的第三个函数
pFunc func2 = (pFunc)*((int*)*(int*)a+2);
func2();
}
/*
* 虚函数表原理:
* 1、虚函数表指针存在对象实例的最前面的位置(为了保证能够获取虚函数的偏移量)
* 意味着通过对象实力的地址得到虚函数表。(有些编译器不支持:Qt:4.8.1没有通过)
* 2、虚函数指针按照声明的顺序存放于虚函数表中
* 3、父类的虚函数在子类的虚函数前面
* 4、子类中覆盖的函数放到父类被覆盖的虚函数的位置,没有被覆盖的函数位置不变
* 5、在多重继承中每个父类都有自己的虚函数表,子类的虚函数北方到第一个父类的虚函数表中
* 6、在多重继承中,子类虚函数会覆盖所有父类虚函数表中的相同的虚函数
*/
/*获取虚函数表中的虚函数的步骤:(一个指针4个字节,所以使用int *)
* 1、通过int*强制转换对象实例的地址 :(int *)&obj 获取虚函数表的地址
* 2、通过地址解引用获取虚函数表: *(int *)&obj
* 3、通过int*强制转换虚函数表,获取虚函数表中的函数地址:(int*)*(int*)&obj
* 4、再次解引用,并类型转换,并保存函数指针:pFunc func = (pFunc)*(int*)*(int*)&obj
*/