【问题标题】:When to put a whole C++ class framework into a DLL?何时将整个 C++ 类框架放入 DLL?
【发布时间】:2016-11-24 14:24:43
【问题描述】:

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

现在我正在考虑如何封装该类框架。我可以像往常一样编写头文件和源文件,然后将它们包含在将使用该框架的应用程序中,以便与应用程序一起编译。

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

您能否向我推荐一种方法,也许是我上面没有提到的其他方法,包括。所有这些选项的优缺点?

【问题讨论】:

  • 我现在没有时间详细回答 - 但请查看 静态库 看看是否符合您的要求。
  • 最小化公开实现的数量始终是一个好主意,尤其是在 C++ 中。使用接口或 pimpl。如果您无法避免异常或公开标准 C++ 库模板类,那么尝试使其变得更好就没有任何意义,只有当客户端应用程序使用完全相同的编译器版本和构建设置时,它才会起作用。
  • @HansPassant 谢谢,我想我明白你的意思,至少在理论上。但这对我的情况意味着什么?客户端应用程序肯定会使用不同的编译器,所以你的意思是 DLL 不适合我吗?
  • 您的机器上有很多由一家公司创建并在另一家公司的代码中使用的 DLL。但是他们不使用本机 C++ 接口,也没有针对 C++ 商定的 ABI。常见的选择是 VM 语言、COM 或 C 风格的界面。

标签: c++ dll


【解决方案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。

他们的代码.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. 确保在边界任一侧分配的内存在同一侧释放。

【讨论】:

  • 非常感谢您的详细回答。通过阅读它,我越来越得出结论,静态库可能是我的更好选择。你同意吗?
  • 绝对可以,但这也需要您为每个编译器类型/版本编译 DLL。最好的办法是以源代码形式给他们库,以便他们自己编译。
猜你喜欢
  • 2010-10-25
  • 2012-04-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多