不说废话,直接上代码。看代码理解。
//=====================通过地址调用类中函数成员地址来调用函数==============================
class base
{
int i;
public:
virtual void f1()
{
std::cout << "base's f1(function in )" << std::endl;
}
virtual void f2()
{
std::cout << "base's f2(function in )" << std::endl;
}
virtual void f3(const char * a)
{
std::cout << "base's f3(function in ):" << a<(pObj);
pAddr = (unsigned long*)*pAddr;
std::cout << classname << "s vtable[" << vindex << "]:0x" << (void*)pAddr[vindex] << std::endl;
const char *bx = "12345678";
if (vindex != 2)
{
((void(*)(void))pAddr[vindex])();
}
else {
if (vindex == 2)
{
((void(*)(const char*))pAddr[vindex])(bx);
}
}
}
//=====================通过地址调用类中函数成员地址来调用函数==============================
int main()
{
//base *b1=new base;
base b1 ; //演示中的原代码的
ShowWtableContent("base",&b1,0);
ShowWtableContent("base", &b1, 1);
ShowWtableContent("base", &b1, 2);
base2 b2;
cout << sizeof(b2) << endl;
cout << &b2 << endl; //对象首地址
cout << (int*)&b2 << endl; //指针首地址,(int*)强制类型转换是为了取四个字节的内容
cout << *(int*)&b2 << endl; //指针的内容,即虚表的地址
cout << *((int*)*(int*)&b2) << endl; //虚表第一个元素即虚函数showa()的地址
cout << *((int*)(*(int*)&b2) + 1) << endl; //第二个元素的地址
typedef void(*Fun)(void); //重命名函数指针类型
Fun pfun;
pfun = (Fun)*(int*)*(int*)&b2; //强制类型转换为该函数指针类型
b2.showa();
pfun();
pfun = (Fun)*(((int*)*(int*)&b2)+1); //强制类型转换为该函数指针类型
b2.showb();
pfun();
pfun = (Fun)*(((int*)*(int*)&b2) + 2); //强制类型转换为该函数指针类型
b2.showc();
pfun();
return 0;
}
以上代码是纯地址取类成员函数,变为函数后的操作 加(int*)的原因: 其实它(int*)的作用是一样的,都是为了取四个字节的内容,至于为什么要这样做就涉及到了指针的基础知识。 我们都知道定义指针变量时一定要声明类型,不同于其他基础类型,定义int变量就是4个字节,定义char变量是1个字节,定义short变量就是2个字节,我们都知道无论是什么类型的指针都占4个字节,那么声明类型到底有什么用呢? 它就是为了限定指针在内存上取变量的长度,这样说可能不太清楚,我们来看代码: #includeint main() { int a=134480385; int* pa=&a; char* pb=&a; short* pc=&a; printf("*pb=%d *pc=%d *pa=%dn",*pb,*pc,*pa); } 显示:*pb=1 *pc=513 *pa=134480385 a的二进制表示为:0000 1000 0000 0100 0000 0010 0000 0001 这样大家看的应该就比较清楚了,char类型的指针pb只会取一个字节,因此取出的数为0000 0001,即1 short类型的指针pc会取两个字节,因此取出的数为0000 0010 0000 0001,即513 同理,int类型指针取四个字节,会全部取出。 好了,现在回到虚表中的(int*)中,现在大家是不是能够理解为什么了呢。 如果不加(int*)编译器就不知道应该取的长度 在取虚表地址的代码中,我们可以看到这个虚表指针是没有名字的, 因此就无法像我们平常使用指针那样直接调用变量来引用内容, 只能通过*(int*)&b的方式获取指针的内容,*(int*)&b就是获取对象b空间上的前四个字节的内容。 同理,虚表虽然像一个指针数组,但是我们不知道它的名字, 也就无法像原来使用数组那样直接使用数组名和下标的方式使用, 只能通过地址来调用内容。*(int*)*(int*)&b,就是在虚表的空间上取四个字节, 它就是第一个虚函数的地址。(int*)(*(int*)&f)+1是第二个元素的地址, 加*取它的内容,即第二个虚函数的地址。



