Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/visual-studio-2008/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 指向整数的成员函数指针?_C++_Visual Studio 2008 - Fatal编程技术网

C++ 指向整数的成员函数指针?

C++ 指向整数的成员函数指针?,c++,visual-studio-2008,C++,Visual Studio 2008,是否可以将虚拟地址作为成员函数指针的整数获取 我试过了 void (AClass::*Test)(); Test = &AClass::TestFunc; int num = *(int*)&Test; 无效(类别::*测试)(); Test=&AClass::TestFunc; int num=*(int*)&Test; 但所做的一切就是给我一个函数的jmp的虚拟地址。我需要实际的函数虚拟地址。虽然我不能确定是否有一种可移植的方法来实现这一点,但我通常建议创建一个静态包装函数来提供对类方法的这

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

我试过了

void (AClass::*Test)(); Test = &AClass::TestFunc; int num = *(int*)&Test; 无效(类别::*测试)(); Test=&AClass::TestFunc; int num=*(int*)&Test;
但所做的一切就是给我一个函数的jmp的虚拟地址。我需要实际的函数虚拟地址。

虽然我不能确定是否有一种可移植的方法来实现这一点,但我通常建议创建一个静态包装函数来提供对类方法的这种外部访问。否则,即使您成功了,您也将创建应用程序与该类实现的紧密耦合。

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

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

我的另一个怀疑是
TestFunc
可能是
virtual
。对于地址被占用的虚拟函数,VC++伪造了一个小thunk来执行vtable查找,并给出一个指向该thunk的指针作为地址。(这样可以确保在实际对象为更派生类型时找到正确的派生函数。还有其他方法可以做到这一点,但这样可以使此类指针成为单个指针,并简化调用代码,但在调用时会产生双跳转。)打开程序的汇编语言输出,并查看结果;事情应该很清楚

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

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

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

更简单的方法是创建一个包含每个虚拟函数代码的非虚拟函数,然后让每个虚拟函数调用该非虚拟函数。这让你的行为和以前一样。如果你想知道代码在哪里,就取非虚函数的地址


(在任何一种情况下,这都很难让工作顺利进行,这会很烦人,而且它相当于VC++特有的——但如果你愿意付出努力的话,你可能会实现它。)

我知道这是一个古老的问题,但由于没有关于这个问题的有意义的答案,我来了

有些事情需要首先考虑。 C++中的成员函数调用约定称为“调用”。此约定几乎与u stdcall相同,唯一显著的区别是,在进行有效调用之前,
ECX
被设置为调用其方法的对象的指针
This

为了说明这一点并同时回答您的问题,让我们假设类
AClass
有一个如下声明的成员函数:
intaclass::myFunction(inta,intb)
,并且我们有一个名为
aClassObject
AClass
实例。 下面是一种相当老练的方法,可以完成您最初要求的操作,并在获得原始指针后“模拟”调用
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

类型的任何实例,它不是虚拟的。但这是一个导入。请尝试关闭增量链接,然后重试。每个外部函数都是通过一段代码来调用的,在这种情况下,这些代码对其实际地址执行jmp。(这可能允许更好地重用以前链接中的数据,因为未更改的模块只需要每个外部函数最多一次修复,而不是每次调用一次。)