成员函数指向整数?

时间:2010-05-28 13:38:01

标签: c++ visual-studio-2008

是否可以将虚拟地址作为成员函数指针的整数?

我试过了。

void (AClass::*Test)();
Test = &AClass::TestFunc;
int num = *(int*)&Test;

但是所有这一切都是让我获得函数的jmp的虚拟地址。我需要实际的功能虚拟地址。

4 个答案:

答案 0 :(得分:4)

我知道这已经过时了,但由于没有有意义的主题答案,所以我走了。

首先需要考虑一些事情。 C ++中的成员函数调用约定称为__thiscall。这个约定几乎与__stdcall相同,唯一的区别在于,在进行有效调用之前,ECX被设置为调用其方法的对象的指针this

为了说明这一点并同时回答你的问题,让我们说类AClass有一个成员函数声明如下:int AClass::myFunction(int a, int b)并且我们有一个AClass的实例叫aClassObject。 这是一个相当hackish的方式来做你最初要求的东西并且在获得原始指针后'{1}} AClass::myFunction调用aClassObject

// declare a delegate, __stdcall convention, as stated above
typedef int (__stdcall *myFunctionDelegate)(int a, int b);
// here's the 'hackish' solution to your question
char myFunctionPtrString[10];
sprintf(myFunctionPtrString, "%d", &AClass::myFunction);
int myFunctionPtr = atoi(myFunctionPtrString);
// now let's call the method using our pointer and the aClassObject instance
myFunctionDelegate myFunction = (myFunctionDelegate)myFunctionPtr;
// before we make the call, we must put a pointer to aClassObject
// in ECX, to finally meet the __thiscall calling convention
int aClassObjectPtr = (int)&aClassObject;
__asm{
     mov ecx, aClassObjectPtr
}
// make the call!
myFunction(2, 3);

当然,实例可以是AClass类型的任何实例。

答案 1 :(得分:3)

不,成员函数指针可以有a variety of sizes(4-16字节或更多,具体取决于平台,请参阅文章中的表格),并且无法可靠地放入整数空间内。这是因为虚函数和继承可以使编译器存储多条信息以调用正确的函数,因此在某些情况下没有简单的地址。

答案 2 :(得分:0)

虽然我不能肯定地说是否有可行的方法来执行此操作,但我通常建议使用静态包装函数来提供对类方法的此类外部访问。否则即使你成功了,你也会创建应用程序与该类实现的紧密耦合。

答案 3 :(得分:0)

如果这是我怀疑它,只需关闭增量链接。与此同时,你得到了正确的答案。

我怀疑TestFunc可能是virtual。对于其地址采用的虚函数,VC ++伪造了一个执行vtable查找的thunk,并给出了一个指向该thunk的指针作为地址。 (这确保当实际对象是更派生的类型时找到正确的派生函数。还有其他方法可以做到这一点,但这允许这样的指针成为单个指针并简化调用代码,代价是双倍当它们被调用时跳转。)打开程序的汇编语言输出,并查看结果;它应该足够清楚发生了什么。

在这里,你得到的是正确的答案,而且无法找到“实际”功能的地址。实际上,虚函数没有命名一个单独的实际函数,它命名哪个派生函数适合于所讨论的对象。 (如果您不喜欢此行为,请将该功能设置为非虚拟。)

如果你真的需要实际功能的真实地址,你有两个选择。令人讨厌的是编写一些代码来扫描thunk以找出函数的vtable索引。然后查看相关对象的vtable以获取该函数。

(但请注意,获取非虚函数的地址将为您提供要调用的实际函数的地址,而不是thunk - 因此您也必须满足这种可能性。指向虚函数的指针和指向非虚函数的指针是相同的。)

更容易制作包含每个虚函数代码的非虚函数,然后让每个虚函数调用非虚函数。这给你的行为和以前一样。如果你想找出代码的位置,请取非虚函数的地址。

(在任何一种情况下,这都很难很好地工作,这会很烦人,而且它会特别是VC ++ - 但如果你愿意付出努力,你可能会成功。 )