c++ - 从 DLL 导出类

标签 c++ visual-c++ dll

我对将类导出为 DLL 有一些疑问。假设我有如下类,并且我希望从 DLL 中导出 BookStore。这样客户端就可以通过 getTitle()BookCollection 中获取 Book 的值。

#ifdef _EXPORTING
#define BOOKSTORE_API __declspec(dllexport)
#else
#define BOOKSTORE_API __declspec(dllimport)
#endif

class Book
{
  std::string title;
  std::string publisher;
  char * getTitle();
  char * getPublisher();
}

class BookCollection
{
  std::vector<Book> books;
  int getBooksCount();
  Book getBook(int location);
}

BOOKSTORE_API class BookStore
{
  BookCollection bookCollection;
  BookCollection getBookCollection();
}

因此,我如何才能成功导出该类以在我可以执行类似操作的其他项目中使用:

BookStore * bookStore = RandomBookStoreGenerator::createBookStore();
std::cout << bookStore->getBookCollection().getBook(0).getTitle() << '\n';

导出 BookStore 是否也会间接导出 BookCollectionBook 或者它们也需要宏来导出?

编辑...

我已经导出了 DLL 并在测试程序中进行了尝试。以下;

BookCollection bookCollection = bookStore->getBookCollection();

结果出错

LNK2001: unresolved external symbol

任何想法,这可能是因为我没有正确导出类吗?

最佳答案

Would exporting BookStore will also export BookCollection and Book indirectly or they also need the macro for export?

他们还需要宏。

编译器只导出标记为导出的内容。它不会自动导出参数,也不会为正在导出的方法和函数返回类型。

如下;

class BOOKSTORE_API Book
{
  std::string title;
  std::string publisher;
  char * getTitle();
  char * getPublisher();
}

class BOOKSTORE_API BookCollection
{
  std::vector<Book> books;
  int getBooksCount();
  Book getBook(int location);
}

class BOOKSTORE_API BookStore {
  // ...
};

您将收到有关未导出成员的额外警告。 如果您对 dll 和 exe 使用相同的编译器和设置,这些是 largely noise and can be silenced (或禁用)。

一个更全面的选择是 pimpl pattern并删除 std::vector 等。阿尔。来自类定义和标准库成员不需要从 dll 中导出。 MSDN has a nice article on this .

class BOOKSTORE_API BookCollection {
protected:
    struct Pimpl;
    Pimpl* pimpl_;
}

// in the cpp compiled into the dll
struct BookCollection::Pimpl {
    // ...
    std::vector<Book> books;
    // ...
}

关于“三规则”和“五规则” 以及 Unresolved 符号...

从dll 导出类时,最好同时导出所有特殊成员,以避免出现未解析的符号错误。如果使用 pimpl 习语,这尤其适用。


[S]uppose all these classes are in different files, should the macro remain the same or [does it] need to be changed per file?

保持宏和包含它的 #define 每个 dll 相同。所以,如果对于单个 dll,它们在三个文件中,那么它们都使用相同的 #define block 。本质上,您是在每个 dll 的基础上控制导入/导出。我还会将定义 block 放入它自己的标题中,并将其包含在每个类的标题中(但这不是必需的)。

[F]rom this simple example, would [a] different msvc compiler version or CRT of the client code raise undefined behaviour as I am aware that returning [an] STL object would cause this. Since in this code, the getter only return primitive C datatype, would it be a problem as well?

是的,不同的编译器版本和标准库可能/会导致问题。例如。即使所有构造函数、赋值运算符和析构函数都从 dll 中导出,客户端仍然需要为此类的对象分配正确的空间量(通过 .new 或在堆栈上)。不同的标准库对于 std::string 等可能有不同的大小,混合它们会造成内存损坏等。在这方面,pimpl 或 NVI(非虚拟接口(interface)或模板模式)更好。

关于c++ - 从 DLL 导出类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37538397/

相关文章:

python - 使用 win32com 模块的带有 CPython 的 RegFree DLL

c++ - 管理 C++ 委托(delegate)生命周期

c++ - Eigen3 矩阵随机

c++ - Visual C++ 的这种奇怪的内联行为是否符合预期?

c++ - Microsoft Visual Studio 2013 链接错误 1104

c++ - visual c++,没有编译器优化的数字代码给出错误的结果

C# 非托管导出不起作用

c++ - 如何显示gdb以正确显示变量?

c++ - vector 的 vector 的初始化是否可以进行范围构造?

dll - 使用 VSIX Visual Studio 扩展部署第 3 方 dll 文件