读书人

C++虚表指针的一个有关问题,和小弟我预

发布时间: 2013-09-29 11:07:08 作者: rapoo

C++虚表指针的一个问题,和我预期的结果有点差距.
我知道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;
}

程序的输出是:
[code]
f
g
h
[/code]
到目前为止看起来一切正常。但是我如果把程序稍微改一下,就不能运行了。我发现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指针不对? 错在哪里?
[解决办法]
你这又不是thiscall,当然没this
两个办法,1、用内联汇编自己move pf 到ecx寄存器
2、使用 fastcall 调用方式,搞定ecx寄存器

[解决办法]
多说一点吧:简单点就这样改

typedef void (_fastcall *pFather)(Father*);

读书人网 >C++

热点推荐