VS2017下为未导出C++接口添加虚析构函数触发LNK2019错误的原因是什么
问题根本原因解析
1. 纯虚析构函数的特殊语法要求
C++标准对纯虚析构函数有特殊规定:哪怕析构函数被声明为纯虚(=0),也必须提供对应的实现。
这和普通纯虚函数完全不同:普通纯虚函数(比如你代码里的foo()、bar())不需要基类实现,多态调用时会直接跳转至派生类的覆盖实现,链接阶段不会要求基类提供对应函数的符号。但析构函数的调用逻辑是编译器强制的:派生类对象析构时,执行完派生类自身的析构逻辑后,一定会自动调用基类的析构函数,无论基类析构是不是纯虚的。你的报错信息里也明确提到,派生类B的析构函数引用了IX的析构函数,就是这个强制调用导致的。
2. 未导出DLL类的符号可见性规则
你最开始没有显式声明IX的析构函数时,编译器会自动生成默认的内联公有析构函数,内联函数的实现会在调用点直接展开,不需要依赖DLL导出的符号,因此不会触发链接错误。
当你显式声明了virtual ~IX() = 0之后,这个析构函数不再是编译器隐式生成的内联实现:
- 如果你没有额外提供
IX析构的实现,链接阶段必然找不到符号 - 哪怕你在DLL内部提供了
IX析构的实现,由于整个IX类没有做导出处理,这个实现的符号也只对DLL内部可见,外部调用的模块(你的test_project)无法访问到该符号,依然会报链接错误。
常见解决方案说明
你提到的两种方案刚好对应上面的两个问题根源:
- 导出
IX接口:DLL会把~IX()的实现符号导出,外部模块链接时可以找到该符号完成重定位 - 给析构函数添加
=default实现:相当于要求编译器生成内联的默认析构实现,调用时直接在调用点展开,不需要依赖DLL的导出符号,无需导出类也能正常编译链接。
内容的提问来源于stack exchange,提问作者TonySalimi
相关产品推荐
相关产品推荐

