Chinaunix
标题:
【结贴】C++虚表指针的一个问题,和我预期的结果有点差距.
[打印本页]
作者:
sampher
时间:
2013-09-27 14:49
标题:
【结贴】C++虚表指针的一个问题,和我预期的结果有点差距.
本帖最后由 sampher 于 2013-09-29 09:28 编辑
我知道C++内存对象模型的基本知识,对于一个有virtual函数的类而言,实例的第一个size_t大小是指向虚表的指针。
因此我写了下面一个在vc下编译的小程序,是可以执行的。
这个类有3个函数,分别叫f/g/h,我不用类的方法调用,而是用指向虚表的实例头部来操作。
class Father
{
public:
int i;
Father(){i=22;}
virtual void f(){printf("f\n");}
virtual void g(){printf("g\n");}
virtual void h(){printf("h\n");}
};
typedef void (*pFather)(Father*);
int main(int argc, char* argv[])
{
Father* pf=new Father;
pFather *pVtable=*(pFather**)(pf);
pVtable[0](pf);
pVtable[1](pf);
pVtable[2](pf);
delete pf;
return 0;
}
复制代码
程序的输出是:
f
g
h
复制代码
到目前为止看起来一切正常。但是我如果把程序稍微改一下,就不能运行了。我发现pVtable[0](pf)在调用f函数的时候,在debug状态下观看f函数调用时的this指针,发现并不是pf。这个非常奇怪。如果我在函数f里面操作一个成员变量,那么打印出来的i的值是一个非常大的值例如17111262。如果我要操作i成员,例如++i,那么程序直接崩溃,像下面这样:
class Father
{
public:
int i;
Father(){i=22;}
virtual void f(){printf("f:%d\n",i);}//这一行打印的i是个无效值。
virtual void g(){printf("g:%d\n",++i);}//++i导致崩溃。
virtual void h(){printf("h\n");}
};
typedef void (*pFather)(Father*);
int main(int argc, char* argv[])
{
Father* pf=new Father;
pFather *pVtable=*(pFather**)(pf);
pVtable[0](pf);
pVtable[1](pf);
pVtable[2](pf);
delete pf;
return 0;
}
复制代码
这是为什么呢? pVtable在调用的时候,类的成员函数的第一个参数默认就是实例的指针对么?
那么上面改过以后的程序为什么this指针不对? 错在哪里?
作者:
linux_c_py_php
时间:
2013-09-27 15:30
有意思?
..
作者:
myworkstation
时间:
2013-09-27 16:00
回复
1#
sampher
你用的什么编译器?通常应该没什么问题的。
作者:
cokeboL
时间:
2013-09-27 16:19
呵呵
作者:
sampher
时间:
2013-09-27 16:41
myworkstation 发表于 2013-09-27 16:00
回复 1# sampher
我在1L写了,VC
作者:
sampher
时间:
2013-09-29 09:27
我知道了,这个代码GCC没有问题,因为GCC是通过堆栈传递参数的方式,第一个参数保存的this指针。而VC编译器在x86平台的优化结果是通过ecx/rcx寄存器保存,所以pVTable指针函数声明的时候要写void (__thiscall *pVTable)(Father*)才行。
这样就可以很好的运行了!
欢迎光临 Chinaunix (http://bbs.chinaunix.net/)
Powered by Discuz! X3.2