标签:ret 理解 返回值 写代码 vptr 转变 大小 遇到 static
定义一个Father类,代码如下:
class Father {
public:
virtual void func1() {cout << "Father::func1" << endl;}
virtual void func2() { cout << "Father::func2" << endl; }
virtual void func3() { cout << "Father::func3" << endl; }
void func4() { cout << "非虚函数:Father::func4" << endl; }
public:
int x = 200;
int y = 300;
static int z;
};
typedef void (*func_t)(void);
int main(void){
Father father;
cout << "对象father地址:" <<(int)&father << endl;
int* vptr = (int*)*(int*)(&father);//函数指针,int*类型
cout << "vptr:" << vptr << endl;
//((void (*)(void))vptr)(); wrong
((void(*)(void))*(vptr))();
((func_t) * (vptr + 0))();
((func_t) * (vptr + 1))();
((func_t) * (vptr + 2))();
? return 0;
}
解释:对father对象取地址得到一个地址,因为地址里面存储的值是一个虚函数表指针,而函数指针占四个字节,因此将地址转为(int *)类型以告诉编译器内存大小,再解引得到虚函数表指针,最后再转为(int *)类型,得到了虚函数表的指针,此时为(int *)类型,最后通过这个int *类型的指针来调用虚函数,如何调用?先得转变指针的类型,因为指针指向的虚函数的返回值是空。
因此定义一个类型
typedef void(*func_t)(void);
然后写代码((func_t) * (vptr + 0))();即可调用虚函数,即先解引虚函数表的指针,得到虚函数的指针,这里注意:区别虚函数表指针与虚函数指针!不然会发生错误,这里需要经过两次解引用!第一次是对&father解引得到虚函数表指针,然后是对虚函数表指针解引得到虚函数指针。
所以不用自定义类型来调用虚函数也很明白了,代码应该这样子写
:((void( *) (void) )) *(vptr))();
千万不要像我之前那样调用((void( *) (void) ))(vptr))(); 将虚函数表指针与虚函数指针混为一谈,闹了笑话。
主要还是理解虚函数表指针这个概念吧!
标签:ret 理解 返回值 写代码 vptr 转变 大小 遇到 static
原文地址:https://www.cnblogs.com/Ybossy/p/12737069.html