最近复习到C++的虚函数,想输出一下虚函数表的地址,但是在编译的时候遇到下面这个错误:
my_virtual.cpp: In function ‘int main()’:
my_virtual.cpp:29:39: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
int *vtbl_addr=((int *)*(int *)(&b)); //②
^
my_virtual.cpp:33:63: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
printf("第一个虚函数地址:%p\n",(void *)*(vtbl_addr));
^
my_virtual.cpp:34:67: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
printf("第二个虚函数地址:%p\n",(void *)*(vtbl_addr + 1));
^
my_virtual.cpp:37:28: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
pfun = (Fun)(*vtbl_addr); //vitural f();
^
my_virtual.cpp:41:34: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
pfun = (Fun)(*(vtbl_addr + 1)); //vitural g();
^
源码如下:
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
using namespace std;
class Base {
public:
virtual void f() { cout << "Base::f" << endl; }
virtual void g() { cout << "Base::g" << endl; }
};
typedef void(*Fun)(void); //函数指针
int main()
{
Base b;
printf("sizeof(int)=%d,sizeof(int *)=%d,sizeof(void *)=%d\n",(int)sizeof(int),(int)sizeof(int *),(int)sizeof(void *));
//int vtbl_addr=((int *)*(int *)(&b)); //①
//int *vtbl_addr=((int *)*(int *)(&b)); //②
unsigned long int *vtbl_addr=((unsigned long int *)*(unsigned long int *)(&b)); //③
printf("虚表地址:%p\n", (void *)vtbl_addr);
printf("第一个虚函数地址:%p\n",(void *)*(vtbl_addr));
printf("第二个虚函数地址:%p\n",(void *)*(vtbl_addr + 1));
Fun pfun = NULL;
pfun = (Fun)(*vtbl_addr); //vitural f();
printf("f() addr:%p\n", (void *)pfun);
pfun();
pfun = (Fun)(*(vtbl_addr + 1)); //vitural g();
pfun();
printf("g() addr:%p\n", (void *)pfun);
return 0;
}
调试过程:
- 最开始是用的一个int类型去保存虚函数表的地址,在windows下编译、运行是通过的,但是放在win10的子系统下编译时碰到了上述警告,提示大小不一样,才想到64位系统指针的大小是8byte
- 然后写下了第二句话,用指针保存地址这总没错吧,但是编译的时候还是碰到了这个警告
- 又试了dynamic_cast来强制转换,emmm,还是不行,最后看cpp参考手册的时候看到dereference这个单词,才想到
(int *)(&b)
是把b
的地址转化为(int *)
,那么解引用的时候得到就是一个int
类型,就是说还是4byte,转化为8byte的指针当然会出错了 - 最后第三种写法是编译运行通过了