首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C语言 >

通过虚函数表调用函数的有关问题

2012-07-23 
通过虚函数表调用函数的问题#includeiostreamusing namespace stdclass good{public:virtual void f(){

通过虚函数表调用函数的问题
#include<iostream>
using namespace std;
class good
{
public:
virtual void f(){int a = 523;cout << a<<"\n"<<this->a<<endl; cout<<"fun::f()"<<endl;}
//此处a 办出为523;this->a为八位数;不会随a的改变而改变,但会随代码的改变而改变
int a;
};

typedef void (*pfun)();

good d;
pfun fun;
int main()
{

fun= (pfun)*((int*)*(int*)(&d));
fun();

}

问:为什么能调用成功,且this->a不报错,a为什么输出正常?

[解决办法]
(pfun)*((int*)*(int*)(&d));
你这一句其实就是强转虚表里的内容,也就是f函数的地址。

把f地址给fun函数指针

这里就涉及到一个问题了,他俩的调用约定。

因为你这两函数都没有参数,所以没有问题

你调用this->a,正常应该是ecx(this) + 偏移去调, 但你现在执行方式使用的是cdecl

调用的时候就不会把this指针压到ecx里


但你的代码我调了下,它在强转过程中,确实把this指针给ecx了,不知道是不是编译器比较聪明

00401978 mov eax,[d (00477740)]
0040197D mov ecx,dword ptr [eax]
0040197F mov dword ptr [fun (00477738)],ecx


[解决办法]
你知道类的对象的内存组成就很简单了,一个类对象前4个字节存放的是虚函数表的指针,虚函数表中存放了所有虚函数的指针,所以
(pfun)*((int*)*(int*)(&d));
这一句的&d的意思是获取该对象的地址,然后*(int*)(&d)这样就获取了虚函数表的指针值
*((int*)*(int*)(&d)),这样就获取了虚函数表中的第一个虚函数的指针值,该对象只有一个虚函数即f(),所以这个地方就获取了这个函数的指针并执行~
后边你就可以简单的当做一个函数在执行了,它输出了一个局部变量,一个问题就是this->a中的this究竟是什么,因为你是直接通过指针转换进行执行,所以此处的this是虚函数的指针,所以此处this->a是虚函数所指向的内存第4-7个字节,换而言之是虚函数f()函数体中的字节
[解决办法]

探讨
经测试也不是函数地址

[解决办法]
探讨
引用:

引用:
经测试也不是函数地址


因为虚函数表在内存中是放在实例的前面的,也就是说既然这个this是虚函数表的地址,也可以说是实例的地址?


当d实例不是全局变量时,是虚函数表地址(int*)*(int*)&amp;d,不是实例地址&amp;d;

[解决办法]
首先解释this指针的问题(注意注释部分)
-------------------_cdecl下的反汇编(lz的代码)--------------
Assembly code
    fun= (pfun)*((int*)*(int*)(&d));00FC1D33  mov         eax,dword ptr [d]   ;虚函数表地址 00FC1D36  mov         ecx,dword ptr [eax] ;此处虽然给ecx赋值了,但其实是虚函数地址00FC1D38  mov         dword ptr [fun (0FD222Ch)],ecx             fun();00FC1D3E  mov         esi,esp 00FC1D40  call        dword ptr [fun (0FD222Ch)] 00FC1D46  cmp         esi,esp 00FC1D48  call        @ILT+1050(__RTC_CheckEsp) (0FC141Fh) 

热点排行