何时将整个C ++类框架放入DLL中?

时间:2016-11-24 14:24:44

标签: c++ dll

我即将编写一个C ++框架,稍后将被不同的C ++应用程序使用。该框架将提供一个主类,该类将由应用程序实例化。该主类将使用框架内的一些其他类。并且将有一些辅助类,由应用程序直接使用。

现在我在考虑如何封装该类框架。我可以像往常一样编写头文件和源文件,然后将那些包含在将使用框架的应用程序中,这样所有内容都将与应用程序一起编译。

但我不确定这是否是我案例中“最好的”方法。将整个框架放入DLL然后将该DLL链接到应用程序是不是可以选择?但是,I also read让DLL导出整个类通常不是最好的想法,并且当使用STL模板作为数据成员时,这种方法可能lead to difficulties

你能否向我推荐一种方法,也许是我上面没有提到的其他方法,包括。所有这些选择的利弊?

1 个答案:

答案 0 :(得分:1)

您可以使用不透明指针创建C接口,这在您的情况下是必需的,因为所涉及的编译器的类型和版本各不相同。请注意,您可能不接受或返回非C类型,除非您还将它们包装在不透明指针中。这并不难,但代表你需要做一些工作。

假设一个类'YourClass',你将创建一个包含C ++类代码的YourClassImpl.h和YourClassImpl.cpp(如果需要)。

YourClassImpl.h

class YourClass
{
    private:
        int value = 12345;

    public:
        YourClass() {}
        ~YourClass() {}

        int getThing() { return value; }
        void setThing(int newValue) { v = newValue}
};

然后,您将创建一个YourClass.h,它将是您的C头文件(由DLL的用户包含),包含一个不透明的指针typedef和C风格接口的声明。

YourClass.h

#ifdef MAKEDLL
#  define EXPORT __declspec(dllexport) __cdecl
#else
#  define EXPORT __declspec(dllimport) __cdecl
#endif

extern "C"
{
    typedef struct YourClass *YC_HANDLE;
    EXPORT YC_HANDLE CreateYourClass();
    EXPORT void DestroyYourClass(YC_HANDLE h);
    EXPORT int YourClassGetThing(YC_HANDLE h);
    EXPORT void YourClassSetThing(YC_HANDLE h, int v);
}

在YourClass.cpp中,您将定义这些函数。

YourClass.cpp

#include "YourClass.h"
#include "YourClassImpl.h"
extern "C"
{
    EXPORT YC_HANDLE CreateYourClass()
    {
        return new YourClass{};
    }

    EXPORT void DestroyYourClass(YC_HANDLE h)
    {
        delete h;
    }

    EXPORT int YourClassGetThing(YC_HANDLE h)
    {
        return h->getThing();
    }

    EXPORT void YourClassSetThing(YC_HANDLE h, int v)
    {
        h->setThing(v);
    }
}

在您的用户代码中,它们将包含YourClass.h。

TheirCode.cpp

#include "YourClass.h"

int ResetValue(int newValue)
{
    YC_HANDLE h = CreateYourClass();
    auto v = YourClassGetThing(h);
    YourClassSetThing(h, newValue);
    DestroyYourClass(h);

    return v;
}

链接到DLL的最常用方法是使用LoadLibrary / GetProcAddress - 我还建议在项目中添加.def文件,以确保函数名称“很好”并且不难访问任何名字装饰。

要注意的一些问题:

  1. 只能在界面上来回传递标准C基本类型。不要使用任何特定于C ++的类型或类。
  2. POD和POD阵列可供您使用,但请注意任何包装或对齐问题。
  3. 异常不得跨越接口边界 - 捕获任何被抛出的内容并将其转换为返回代码或等效内容。
  4. 确保在边界两侧分配的内存在同一侧解除分配。