我可以在DLL中组织类吗
Can I organize classes in DLLs?
我承认这个问题听起来很笼统。但毕竟,从DLL导出类是一个普遍而困难的话题,坦率地说,我目前在相当普遍的层面上感到困惑。
简短的问题:C++中的面向对象编程和DLL是如何结合在一起的?
长问题:读过这篇文章后,我有点失望和困惑,因为我想知道如果DLL边界不允许共享对象(假设两个DLL使用了不同的编译器或编译器版本),面向对象编程如何与DLL一起工作。导出类的唯一选项是(如这里或这里所解释的):
- 导出create和delete方法(C风格,悬挂指针的危险,没有对象作为参数,丑陋)
- 导出一个纯虚拟类和一个工厂函数,该函数创建从纯虚拟类派生的实际实现类的实例(需要继承,需要处理对象删除)
例如,我想把公共实用程序类放在一个DLL中,然后在其他DLL的几个类中使用,这些类本身也在其他DLL中使用。我该怎么做?这是不是一种定义不清的上课方式?
附加问题:如果我导出一个具有指向实现的指针的类,这相当于导出一个纯虚拟类和一个工厂函数吗?还是导出的成员函数必须是虚拟的?
编辑:如果重要的话,我在使用Visual Studio 2010的Windows7上。迁移到较旧的Visual Studio使我对这个问题很敏感。
TL;DR:这取决于情况。
简单案例
当两个DLL(或一个DLL和一个可执行文件)是用相同的编译器和编译器版本构建的,并且它们使用相同的运行时风格(调试或发布),并且它们链接到运行时的动态版本时,您可以随心所欲。例如,跨DLL边界删除。
不那么简单的案例
当一个DLL链接到调试运行时,另一个链接到发布运行时时,事情会变得更加复杂。这是因为调试运行时具有不同的STL模板,用于调试目的。例如,您不能操作从发布DLL中的调试DLL分配的std::向量,反之亦然。只要您将这些STL模板限制在正确的DLL中,一切都应该正常。显然,如果您自己公开不同的ABI,例如在#ifndef NDEBUG
块中声明一个成员,就会遇到问题。
根据调试DLL使用的模板,您可能需要使用_CRT*
定义来强制执行一些操作。
您还应该从同一个DLL创建和销毁对象。
可怕的(又称现实世界)案例
当编译器版本不匹配时,当至少有一个DLL与静态运行时链接时打开。
你会遇到很多ABI问题。唯一安全的做法是通过extern "C"
(广泛地)依赖C ABI。如果在运行时加载DLL,这可能也是您想要做的。
在这一点上做一件好事:
- 用C编写DLL++
- 不要使用C++ABI公开(
dllexport
)任何内容 - 围绕C++代码编写一个薄薄的C包装器
- 使用
__declspec(dllexport)
公开此C API - 围绕公开的C API编写一个仅限头的C++包装器
然后,客户端将使用您的仅头的包装器,因此对DLL代码的每次调用都将使用C ABI进行,它非常稳定,不太可能中断。
我已经很久没有写你链接的问题了,但让我试着帮你。
简短的问题是:C++中的面向对象编程和DLL是如何结合在一起的?
这完全取决于你的物体暴露了什么。如果您的对象返回的是纯C值,那么您应该没事。如果您的对象返回包含纯C值的POD类,那么您也应该可以。在那对问答中,我试图解决的头痛问题几乎完全与STL有关。
为了回答自然的后续问题,STL在DLL中的表现非常糟糕。由于不同的封装、成员重新排序等原因,C++类存在固有的跨编译器兼容性问题。STL增加了一层潜在的不兼容性,因为当构建到调试DLL中时,可以添加额外的成员。
例如,我想把公共实用程序类放在一个DLL中,然后在其他DLL的几个类中使用,这些类本身也在其他DLL中使用。我该怎么做?
在未能成功传递STL类型之后,我最终将C++类封装在一个层中,该层将它们转换为C类和从C类转换过来。在可能的情况下,我返回了基本的数据类型。在必须分配内存的地方(string
、vector
等),我最终得到了c样式的创建/删除函数。我相信我仍然公开了一个纯虚拟接口,以保护尽可能多的实现细节;我只是没有尝试直接通过DLL边界传递任何STL对象。
如果我导出一个具有指向实现的指针的类,这等效于导出一个纯虚拟类和一个工厂函数吗?还是导出的成员函数必须是虚拟的?
如果我正确理解这个问题,你两个都想做。
struct MyDLL
{
virtual void DoSomething() = 0;
virtual int AddSomething(int argument1, int argument2) = 0;
}
extern "C" __declspec(dllexport) MyDLL* GetMyDLL();
现在,您的调用者可以调用GetMyDLL
,并有一个指向类的指针,这样您就可以安全地在后台实现虚拟函数,而不用担心调用者看到您在做什么。
- 我可以从 lua 5.0.2 加载用 c++ 编写的 lua 5.3.5 dll 吗?
- 我可以從 DLL 中匯出 Windows CRITICAL_SECTION嗎?
- 为什么我可以在EXE上编译DLL
- DLL:当 SDK 头文件不使用 __declspec(dllexport) 时,我可以使用它吗
- 我可以用C++/WinRT编写一个DLL,供windows桌面应用程序(而不是UWP)或Unity插件使用吗
- 我可以加载与库静态链接的 dll 吗?
- 我可以在 Win32 DLL 中使用 LoadLibrary 吗?
- 我可以将Visual Studio 2015头文件编译成dll并在VS2013中使用它吗?
- 是否可以将 SDL .lib、.dll 和头文件放在某个地方,以便我可以在 Visual Studio 2017 RC 项目中键入 #include < SDL2.h>?
- 我可以找到哪个dll
- 我可以用具有相同功能名称的多个DLL加载元素吗?
- 我可以将使用v120_xp工具集构建的静态库链接到使用VS2013中的v120工具集创建的EXE/DLL中吗
- 我可以在DLL中组织类吗
- 我可以将输出从 C DLL 重定向到我的 c# log4net 输出吗?
- 卸载DLL后,我可以存储在DLL中创建的对象吗
- 我可以用VC++2008创建Dll并在VC++6中使用它吗
- 我可以将dll加载到共享内存中吗
- 我可以在DLL边界使用“enum class”作为函数的参数类型吗
- 我可以在MONO中创建一个dll/库,用于Linux下的C++程序吗
- 我可以使用NPAPI在一个DLL中创建多个插件吗