- 场景一:声明和实现都在 `.h` 文件中时,给外部模块用,需不需要导入导出 ?
- 场景二:声明和实现分开在 `.h` `.cpp`文件中时,给外部模块用,需不需要导入导出 ?
- 场景三:声明和实现分开在 `.h` `.cpp`文件中时,给外部模块用,只导出需要的函数接口行不行 ?
- 场景四: 给外部使用的枚举需要显式导入导出么?常量需要导入导出么?
- 释疑与总结
- 题外话
通常情况下,开发者在用到 __declspec(dllexport) 和 __declspec(dllimport) 时,大多数是为了本模块的接口供模块外的功能使用。但在开发过程中,常常保持着 “不知道该不该用,但用了不会出错” 的原则,从而滥用的情况,现在就几种典型场景进行说明。
我们编写如下测试代码:
两个独立的 dll 模块 panny_dll panny_dll_test。
我们在 panny_dll 模块中定义我们需要验证的对象。在 panny_dll_test 中测试。
运行结果如下:
说明这种情况下,不需要导入导出标识。
链接报错:
说明,声明、实现分开写在.h .cpp文件中时,如果不导出,会出现问题。
原因是外部在调用这个接口时,没有被导出,链接时找不到这个函数。
我们在写这个函数的时候也确实没有导出,所以会出现这种情况。
场景三:声明和实现分开在 .h .cpp文件中时,给外部模块用,只导出需要的函数接口行不行 ?那么为什么声明和实现都写在 .h 中的时候没问题呢?
这就涉及到C++ 的编译链接逻辑了。
我们在编译时,一般会将.cpp编译为.obj文件,一个.cpp对应一个.obj;链接时,根据需要将多个obj组成.lib,或者生成.dll。
而导入导出的本质,其实就是为了让其他模块的代码感知本模块的.cpp文件。
那么没有 .cpp 文件,理论上就没有 dll 文件,用户拿到包含实现代码的头文件就应该可以用,这就不存在声明导入导出了。
运行结果:
说明,可以在不导出类的情况下,按需导出接口函数。
结果:
说明: 枚举和常量如果在头文件中定义了,外部是可以通过包含头文件直接使用的。
导入导出的本质是为了让其他模块的代码感知本模块的.cpp文件。
我们在编译时,一般会将.cpp编译为.obj文件,一个.cpp对应一个.obj;链接时,根据需要将多个obj组成.lib,或者生成.dll。
-
对于声明和实现分别在.h和.cpp的部分,如果没有标识导入导出,那么默认的只能在本模块使用。
-
如果声明和实现均在.h中的话,那其实是没有对应的.dll文件的,默认的是全局作用域,对所有模块都可见。我们看到的枚举就是这种情况。还有全部的模板类都这这种情况。
-
如果声明和实现分别在.h和.cpp的部分,并且标识导入导出,那就是本模块能使用,外部模块也能使用。
doxygen 在根据注释生成文档时,有一个很有意思的现象,就是当且仅当枚举被标识导入导出时,会注释识别失败,官方文档也没找到有效说明。也许是有意为之,也许就是个隐藏的BUG。不过将枚举标识导入导出,本身就是多此一举的,或许 doxygen 也有这种考量,才会不识别吧。



