我有一个使用多个C ++ DLL的非托管Win32 C ++应用程序。每个DLL都需要使用类Foo - 定义和实现。
Foo.h和Foo.cpp在哪里生存,以便DLL链接并且最终不会在内存中复制代码?
这是否合理?
[编辑] 所有下面的答案和评论中有很多好的信息 - 不仅仅是我标记为答案的那些。感谢大家的投入。
答案 0 :(得分:5)
通过DLL以类的形式提供功能本身很好。但是,您需要注意从实现中分离出接口。多么小心取决于你的DLL的使用方式。对于保留在内部的玩具项目或公用事业,您可能不需要考虑它。对于将由who-knows-which编译器下的多个客户端使用的DLL,您需要非常小心。
考虑:
class MyGizmo
{
public:
std::string get_name() const;
private:
std::string name_;
};
如果第三方将使用MyGizmo
,则此课程将使您无法头疼。显然,私有成员变量是一个问题,但get_name()
的返回类型也是一个问题。原因是因为std::string
的实现细节是其定义的一部分。标准规定了std::string
的最小功能集,但编译器编写者可以自由选择。可能有一个名为realloc()
的函数来处理内部重新分配,而另一个可能有一个名为buy_node()
的函数。数据成员也是如此。一个实现可以使用3 size_t
和char*
,而另一个实现可以使用std::vector
。关键是您的编译器可能认为std::string
是n个字节并且具有某些成员,而另一个编译器(或者甚至是同一编译器的另一个补丁级别)可能认为它看起来完全不同。
对此的一个解决方案是使用interfaces。在DLL的公共头文件中,声明一个表示DLL提供的有用功能的抽象类,以及创建类的方法,例如:
class MyGizmo
{
public:
static MyGizmo* Create();
virtual void get_name(char* buffer_alloc_by_caller, size_t size_of_buffer) const = 0;
virtual ~MyGizmo();
private:
MyGizmo(); // nobody can create this except myself
};
...然后在你的DLL的内部,你定义一个实际实现MyGizmo
的类:
class MyConcreteGizmo : public MyGizmo
{
public:
void get_name(char* buf, size_t sz) const { /*...*/ }
~MyGizmo() { /*...*/ }
private:
std::string name_;
};
MyGizmo* MyGizmo::Create()
{
return new MyConcreteGizmo;
}
这可能看起来很痛苦,而且确实如此。如果您的DLL仅由一个编译器在内部使用,则可能没有理由去解决问题。但是,如果您的DLL将在内部或外部客户端使用我的多个编译器,那么这样做可以避免重大的麻烦。
答案 1 :(得分:2)
使用__declspec dllexport将类导出到DLL的导出表,然后在其他项目中包含头文件,并链接到主DLL的导出库文件。这样实现很常见。
答案 2 :(得分:2)
Foo住在哪里?在另一个dll。
合理吗?不是真的。
如果你声明一个这样的类:
class __declspec(dllexport)Foo {...
然后msvc将导出该类的每个成员函数。但是,由于对类定义的任何小的更改而没有相应的每个消耗dll的重建,所得到的dll非常脆弱,这意味着消耗代码将为工厂函数未执行的任何堆栈和堆分配分配不正确的字节数。同样,内联方法将编译为消费dll并引用类的旧布局。
如果所有的dll总是在一起重建,那就继续吧。如果不是 - 不要:P