#include <stdio.h>
#include <stdlib.h>
#include <string.h>
class A{
protected:
virtual void fun(){
printf("class:a function:fun\n");
}
virtual void fun2(){
printf("class:a function:fun2\n");
}
};
class B:public A{
protected:
void fun(){
printf("class:b function:fun\n");
}
void fun2(){
printf("class:b function:fun2\n");
}
};
int main(){
//输入和输出重定向
freopen("in.txt","r", stdin);
freopen("out.txt", "w", stdout);
void (*fun)(A*);
A* pa = new B();
long fp;
memcpy(&fp, pa, 4);
memcpy(&fun, reinterpret_cast<long*>(fp), 4);
fun(pa);
memcpy(&fun, reinterpret_cast<long*>(fp)+1, 4);
fun(pa);
delete pa;
return 0;
}
输出结果如下:
class:b function:fun
class:b function:fun2
百度百科的解释:
void (*fun)(A*); 这段定义了一个
函数指针名字叫做fun,而且有一个A*类型的参数,这个函数指针待会儿用来保存从vtbl里取出的函数地址
A* p=new B(); new B是向内存(内存分5个区:全局名字空间,自由存储区,寄存器,代码空间,栈)自由存储区申请一个内存单元的地址然后隐式地保存在一个
指针中.然后把这个地址赋值给A类型的指针P.
.
long fp; 这个long类型的
变量待会儿用来保存vptr的值
memcpy(&fp,pa,4); 前面说了,他们的实例对象里只有vptr
指针,所以我们就放心大胆地把pa所指的4bytes内存里的东西复制到fp中,所以复制出来的4bytes内容就是vptr的值,即vtbl的地址
现在有了vtbl的地址了,那么我们现在就取出vtbl第一个slot里的内容
memcpy(&fun, reinterpret_cast<long*>(fp), 4); 取出vtbl第一个slot里的内容,并存放在
函数指针fun里。需要注意的是fp里面是vtbl的地址,但fp不是
指针,所以我们要把它先转变成指针类型
fun(pa); 这里就调用了刚才取出的函数地址里的函数,也就是调用了B::fun()这个函数,也许你发现了为什么会有参数p,其实类
成员函数调用时,会有个this
指针,这个p就是那个this指针,只是在一般的调用中
编译器自动帮你处理了而已,而在这里则需要自己处理