从DLL导出类

时间:2016-05-31 06:32:47

标签: c++ visual-c++ dll

我在将类导出为DLL时有些疑惑。假设我有以下类,我希望从DLL导出BookStore。因此,客户可以通过例如:BookBookCollection获取getTitle()之外的值。

#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:未解析的外部符号

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

1 个答案:

答案 0 :(得分:3)

  

导出BookStore还会间接导出BookCollectionBook,还是需要宏导出?

他们也需要宏。

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

如下;

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;
    // ...
}

关于三&#34;的规则以及&#34;规则五&#34; 和未解决的符号......

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

  

[S]假设所有这些类都在不同的文件中,如果宏保持不变或者是否需要根据文件进行更改?

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

  

[F]这个简单的例子,将[a]不同的msvc编译器版本或客户端代码的CRT引发未定义的行为,因为我知道返回[an] STL对象会导致这种情况。因为在这段代码中,getter只返回原语C数据类型,它也会成为问题吗?

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