我在将类导出为DLL时有些疑惑。假设我有以下类,我希望从DLL导出BookStore
。因此,客户可以通过例如:Book
从BookCollection
获取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
还会间接导出BookCollection
和Book
,还是需要宏导出?
编辑...
我已导出DLL并在测试程序中尝试过。以下;
BookCollection bookCollection = bookStore->getBookCollection();
导致错误
LNK2001:未解析的外部符号
任何想法,这可能是因为我没有正确导出类吗?
答案 0 :(得分:3)
导出
BookStore
还会间接导出BookCollection
和Book
,还是需要宏导出?
他们也需要宏。
编译器仅导出标记为导出的内容。它不会自动导出参数,也不会返回正在导出的方法和函数的类型。
如下;
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(非虚拟接口或模板模板)更好。