C++中纯虚析构函数类外定义报错原因咨询
为什么纯虚析构函数必须定义,而普通纯虚函数不需要?
咱们先澄清一个常见误解:纯虚析构函数是完全可以在类外定义的,你的程序1报错不是因为“无法类外定义”,而是因为你漏了给基类的纯虚析构函数提供实现——不管是类内还是类外,纯虚析构函数都必须有定义。下面咱们一步步拆解原因:
一、纯虚析构函数的特殊调用规则
C++中,析构函数的调用是链式触发的:当派生类对象被销毁时,会先执行派生类的析构函数,然后自动调用基类的析构函数——这个规则不受基类析构是否为纯虚函数的影响。
也就是说,哪怕你把基类析构声明为纯虚(virtual ~base() = 0;),它也必须有定义,因为派生类的析构函数一定会去调用它。
分析你的三个程序:
程序1的错误根源
struct base{ virtual ~base() =0; }; struct derived: public base{ ~derived(); }; derived::~derived(){} // 类外定义派生类析构 int main(){}
这里,派生类的析构函数在类外定义时,编译器会生成完整的函数代码,其中必然包含对base::~base()的调用。但你只声明了基类的纯虚析构,没有提供任何实现,所以链接器找不到base::~base()的代码,就会抛出“未定义符号”的错误。
如果给基类的纯虚析构补上类外定义,程序1就能正常编译运行:
struct base{ virtual ~base() =0; }; base::~base() {} // 补上基类纯虚析构的类外实现 struct derived: public base{ ~derived(); }; derived::~derived(){} int main(){}
程序2为什么没报错?
struct base{ virtual ~base() =0; }; struct derived: public base{ ~derived(){} }; // 类内定义派生类析构 int main(){}
因为你的main函数是空的,没有创建任何derived对象。编译器和链接器会优化掉未被使用的derived::~derived()函数,自然也不会触发对base::~base()的调用需求。如果在main里加一句derived d;,程序2也会出现和程序1一样的链接错误。
二、普通纯虚函数的不同逻辑
普通纯虚函数(比如程序3里的func)不需要基类提供定义,核心原因是:
- 普通纯虚函数的作用是强制派生类提供覆盖实现,程序运行时只会调用派生类的覆盖版本,基类的纯虚函数不会被自动调用(除非你显式写
base::func()去调用它)。 - 所以只要派生类提供了定义,即使基类的纯虚函数只有声明没有实现,也不会有链接问题——就像程序3那样,你在类外定义了
derived::func(),基类的func只有纯虚声明,完全可以正常编译运行。
程序3的代码参考
struct base{ virtual void func() =0; }; struct derived: public base{ void func(); }; void derived::func(){} int main(){}
总结
- 纯虚析构函数必须有定义(类内或类外都支持),因为派生类析构会自动调用它;
- 普通纯虚函数不需要基类定义,因为运行时只会调用派生类的覆盖版本;
- 你的程序1报错是因为漏写了基类纯虚析构的实现,不是不能在类外定义纯虚析构。
内容的提问来源于stack exchange,提问作者Mathew
相关产品推荐
相关产品推荐

