导出 DLL C++ 类,关于 .def 文件的问题
Posted
技术标签:
【中文标题】导出 DLL C++ 类,关于 .def 文件的问题【英文标题】:Exporting DLL C++ Class , question about .def file 【发布时间】:2010-09-16 05:16:31 【问题描述】:我想在我的项目中使用隐式链接,nmake 真的想要一个 .def 文件。问题是,这是一个类,我不知道在导出部分写什么。 谁能指出我正确的方向?
错误信息如下:
NMAKE : U1073: 不知道如何制作 'DLLCLASS.def'
P.S:我正在尝试使用 Windows CE Platform Builder 进行构建。
【问题讨论】:
使用 .DEF 文件是导出 C++ 代码的最糟糕方式。我希望 Greg Hewgill 描述的 dllimport/dllexport 关键字可以用在你的案例中,如这个 MS 链接所示:msdn.microsoft.com/en-us/library/ms924233.aspx 【参考方案1】:如果我没记错的话,你可以在 class 上使用__declspec(dllexport)
,VC++ 会自动为与该类相关的所有符号(构造函数/析构函数、方法、vtable、typeinfo、等)。
微软有更多关于这个here的信息。
【讨论】:
或者只导出你关心的符号。 link【参考方案2】:您始终可以使用dumpbin /symbols myclass.obj 找到成员函数的修饰名称
就我而言
class A
public:
A( int )
;
dumpbin
转储显示符号 ??0A@@QAE@H@Z (public: __thiscall A::A(int))
将此符号放入 .def 文件会导致链接器在导出符号中创建 A::A(int) 符号。
但是!正如@paercebal 在他的评论中所说:手动输入修饰(损坏)名称是一件苦差事 - 容易出错,而且很遗憾,不能保证跨编译器版本可移植。
【讨论】:
【参考方案3】:我找到了成为抽象工厂的最佳途径。
首先定义一个纯虚拟基类。这是一个没有实现的类,一个纯粹的虚拟接口类。
您可以导出这个虚拟基“抽象接口”类,但没有真正的理由这样做。当调用者使用它时,他们将通过指针(PImpl,或指向实现的指针)使用它,因此调用者所知道的只是一个简单的内存地址。 Def 文件虽然需要更多的工作来跟上,但提供的好处超出了 __declspec(dllexport) 所能达到的范围。你问有什么好处?我们会解决的,你等着。
让您的真实类公开继承自虚拟基础。现在创建一个工厂方法来构造您的对象和一个“release”ish 可调用析构函数来执行清理。将这些方法命名为“ConstructMyClass”和“ReleaseMyClass”。请,请替换“MyClass” :-)
如果需要任何参数(普通旧数据:整数、字符等),那些工厂/发布方法应该只采用 POD 类型。返回类型应该是你的虚拟抽象接口基类——或者更确切地说,一个指向它的指针。
IMyClass* CreateAnObjectOfTypeIMyClass();
也许现在很明显为什么我们需要虚拟基类?由于虚拟接口类没有实现,它本质上是所有 POD 类型(某种),因此大多数调用者(如 Visual Basic、C 或截然不同的 C++ 编译器)都可以理解该类的“数据类型”。
如果您足够花哨,您可以绕过对“手动发布”方法的需求(抱歉,必须这样做)。如何?通过智能指针和 pImpl 类型的体系结构在类中管理您自己的资源,因此当对象死亡时,它会自行清理。这样做意味着你的班级是,用我们的圣人和救世主Scott Meyers, "easy to use correctly and hard to use incorrectly" 的不朽话语,让调用者无视清理的需要。让我们当中从未忘记调用“.close”的人投下第一块石头。
也许这种架构听起来很熟悉?它应该,它基本上是 COM 的微机版本。好吧,至少是接口、工厂构建和发布的概念。
最后,您已经为您的类导出了接口,创建(并导出)了 Create 和 Destroy 方法,现在调用者可以调用您的 PleaseConstructMyClass 工厂函数让您的 DLL 在其接口的幌子下返回一个完全构造、完全实现和完全烘焙的对象。他们可以调用您类的所有公共方法(至少是抽象虚拟接口中的方法)并做所有有趣的事情。
当他们完成了工厂函数返回的对象时,他们可以调用“ReleaseMyClass”函数来要求你的DLL清理对象的资源,或者你可以帮助他们通过让你的类自己清理,使“ReleaseMyClass”方法变得多余和无用。
如果有人对使用 Def 文件和界面的具体收益和权衡感兴趣(除了我的盲目说的话),请提出来,我们可以更深入地挖掘。
你不只是喜欢这些东西吗?
【讨论】:
哇,读起来真棒,我很想进入 DEF 文件的内容。此外,您不会碰巧有实现此架构的示例代码吗?挺有意思的,不过看代码总是比英文翻译容易哈哈 不会使用 STL 类(如 unique_ptr、shared_ptr、字符串和向量)作为返回或参数类型会破坏所有交叉编译器(想想 MSVC-MinGW)兼容性吗?【参考方案4】:解决方法如下:
由于导出了一个类,还需要在.def文件中添加导出的方法
我不知道如何导出构造函数,所以我使用了工厂方法(静态),它将返回对象的新实例
其他函数将通过在.def文件中添加正常的导出声明来导出
希望有人能从这些信息中受益。
【讨论】:
这不是解决方案,而是解决方法。您可以在 .def 文件中添加构造函数符号。以上是关于导出 DLL C++ 类,关于 .def 文件的问题的主要内容,如果未能解决你的问题,请参考以下文章