我有这个代码:(exe)
#include <Windows.h>
#pragma comment(lib, "user32.lib")
class Dummy;
typedef void(Dummy::*Referece)(int i);
typedef void(*InitCall)(void*, Referece);
class Dummy
{
public:
Dummy(){}
void callMe(int val)
{
MessageBoxA(0, "ok", "ok", 0);
}
};
int main()
{
Dummy* obj = new Dummy();
HMODULE ha= LoadLibraryA("aa.dll");
InitCall val = (InitCall)GetProcAddress(ha, "Init");
val(obj, &Dummy::callMe);
}
和我的 dll: (.h)
#pragma once
#define DLL_EXPORT __declspec(dllexport)
class Test;
typedef void (Test::*Reference)(int a);
#ifdef __cplusplus
extern "C"
{
#endif
void DLL_EXPORT Init(Test* Object, Reference reference);
#ifdef __cplusplus
}
#endif
(.cpp)
#include "your.h"
void DLL_EXPORT Init(Test * Object, Reference reference)
{
(Object->*reference)(1);
}
我复制了系统,应该是这样的,因为我无法在一侧更改代码。为什么我会遇到访问冲突?调用 "val(obj, ref)" 我希望有一个指向类的指针 + 方法调用的偏移量。
指向成员的指针不是“类中的偏移量”。没有这样的事情。在某些情况下(例如指向具有简单继承层次结构的类中的虚拟成员函数的指针),它的实现可以由这样的偏移量(加上可能的其他一些数据位)组成。
但是,对于非虚拟函数(如您的示例中),它可能有一个指向其下方的函数的普通指针。非虚拟函数不存储在任何带有“偏移量”的“表”中(至少没有理由以这种方式存储它们),它们很可能作为普通的沼泽标准函数实现,名称错误且前置参数.
指向成员的指针是 C++ 的一个有点棘手的部分,主要是因为没有明显的实现概念映射,并且不同的编译器可以以不同的方式处理它们。相信 avoid (Dummy::*)(int)
和void (Test::*)(int)
是二进制兼容是非常脆弱的。
通常,您不能期望指针的二进制表示与指向Dummy::callMe
成员函数的指针的二进制表示有任何相似之处Test
,因为它可能过多地依赖于 和 的定义,Dummy
以及Test
编译器如何实现指向成员的指针.
最重要的是,Visual Studio 的编译器在默认情况下处理指向成员的指针的方式是不符合标准的(因此,从大多数角度来看,这是错误的)。这种默认处理是为了正确形成指向类成员的指针,编译器需要看到类的定义。原因是成员指针的最通用实现非常大(我相信是 4 个原生词),因为它必须考虑虚拟继承等。没有 virtuals 的单基类的最常见情况可以放在本地词中。
因此,如果您想可靠地使用完全标准的C++ 构造,例如接受指向其定义在站点上不可见的类成员的指针,则必须使用编译标志/vmg
。这样,将始终使用最通用的表示。
默认行为 ,根据 的定义/vmb
优化二进制表示(包括大小!)。因此,不可能在这种行为生效的情况下创建像您这样的 typedef。A::*
A
至于你的选择是什么:
如果您绝对必须通过 C 风格的接口,强制使用 C 风格的函数作为调用回调的一侧的回调,并在注册侧创建一个包装 C 风格的函数。像这样的东西:
class Dummy
{
void callMe(int) {}
};
extern "C" void fw_Dummy_callMe(void *self, int i)
{ static_cast<Dummy*>(self)->callMe(i); }
加
#ifdef __cplusplus
extern "C"
{
#endif
void DLL_EXPORT Init(void* Object, void (*reference)(void*, int));
#ifdef __cplusplus
}
#endif
如果您可以在接口中使用 C++(即 DLL 接口两侧的编译器和版本将始终相同),您可以使用指向成员函数的指针,前提是:
/vmg
在构建 DLL 及其客户端时使用。本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句