关于c ++:将类导出到DLL

exporting classes to DLLs

本问题已经有最佳答案,请猛点这里访问。

你好,我现在对dlls有点困惑,所以我来这里是想问一下编程中有哪些专业人士所以我得到了一个叫做gui.h和gui.cpp的类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class GUI
{
    public:
        GUI(void);
        virtual ~GUI();
        void Draw(float x,float y,float z);
        void Texture(int num);
        bool Shutdown();
        void TextureON(int num);
        void TextureOFF(int num);

    private:
    GUIWeapon * Weapon;
    GUIWeaponA * Weapona;
    GUIArrow * Arrow;
    GUIHP * hp;
    GUIStop * stop;
    GUISpeed * Speed;
    float XCam,YCam,ZCam;
    bool DrawStop;

};

那么,我应该如何将它导出到一个dll中呢?我已经创建了dll,但没有使用类。那么,我应该如何声明构造函数、析构函数和调用其他头中的其他gui函数呢?


您不指定编译器或操作系统,但是如果这是Windows和微软C++,那么您可以在类上使用y-xDeScript(DLExcel)从DLL导出它。然后在同一个类上使用uudeclspec(dllimport),当您包含要在其他地方使用的头时。

但是,我倾向于建议不要从DLL导出类。如果所有的DLL总是一起装运并一起构建,那么这是一个不错的计划。[其中dll仅用于延迟代码加载]。如果您使用DLL来提供单独提供的实际组件,那么应该使用实际的可版本化抽象,如COM。

马丁


像这样导出:

1
2
class __declspec(dllexport) GUI
{...}

导入方式:

1
2
class __declspec(dllimport) GUI
{...}

或者简单地定义如下宏:

1
2
3
4
5
#if _DEFINE_THIS_IN_YOUR_DLL_
    #define CLASS_IMPORT_EXPORT __declspec(dllexport)
#else
    #define CLASS_IMPORT_EXPORT __declspec(dllexport)
#endif

直接使用:

1
2
3
class CLASS_IMPORT_EXPORT GUI
{
};

请确保为dll及其客户机都有一个头文件。

但需要注意的是,dll中的sizeof类和客户机(exe)必须相同。例如,可能会发生这样的情况:您有一个数组,其大小被定义为宏。在dll中,它可能是100,但在exe中,它可能是200(出于任何原因)。这只会破坏类,当您调用某个函数时,this指针是正确的;但类(即sizeof(GUI-in-DLL) != sizeof(GUI-in-EXE)指针)不是正确的。

导出类还意味着公开包含它的所有数据成员。这意味着要公开所有其他类/结构/typedef/私有变量等等。对于这个解决方案,我们可以计算所有数据成员的大小(比如154字节),并在类中声明一个char filler[154](用于隐藏实际数据)。虽然这实际上是可行的,但编译器链接器、调试器等不会有任何问题,但对于程序员来说,这是不灵活的。

不管是否用填充字节隐藏实际的数据声明,您还必须确保pragma packing。首先,如果dll有4个字节的打包,而exe有(即使是错误的)1个字节的打包,那么您就陷入了混乱。这个错误很难被发现!

最佳解决方案IMO是导出一个具有指向实现实际功能的类的指针的类。这意味着GUI_Internal/GUI_Core和仅导出GUI具有这些类的指针:

1
2
3
4
5
class IMPORT_EXPORT GUI
{
   GUI_Internal* pInternal; // 4/8 bytes only! EXACT
   // ... Export functions
};

但这将要求DLL客户端(在编译器级别)知道GUI_Internal是什么。为此,只要有一个typedef

1
2
3
4
5
#if _DEFINE_THIS_IN_YOUR_DLL_
typedef GUI_Internal* ClassPointer;
#else
typedef void* ClassPointer
#endif

并使用它:

1
2
3
4
class CLASS_IMPORT_EXPORT GUI
{
ClassPointer pointer; // Name is something else! ...
};

这显然需要您使用gui_internal实例分配指针,并将函数转发给该类。