You need to enable JavaScript to run this app. C++特殊成员函数不被继承的含义及子类调用父类析构疑问
优惠活动
大模型
产品
解决方案
定价
更多

C++特殊成员函数不被继承的含义及子类调用父类析构疑问

问题解答

一、「构造函数、析构函数、重载赋值运算符、拷贝构造函数不被继承」的准确含义

首先明确C++中「成员被继承」的判定标准:如果基类的某成员被派生类继承,那么派生类将原生拥有该签名的成员作为自身成员,无需额外声明即可直接作为自身接口使用。
上述特殊成员不被继承,具体指:

  • 构造函数:基类的构造函数不会自动成为派生类的构造函数。比如基类A有构造函数A(int, double),派生类B默认不会自动生成B(int, double),除非你显式定义派生类构造函数,或者用using A::A;显式把基类构造引入派生类作用域。
  • 析构函数:派生类的析构函数是独立于基类的专属成员,不会复用基类的析构签名。派生类析构执行完成后会自动调用基类析构,但这是编译器插入的调用逻辑,不代表析构是继承来的。
  • 拷贝构造、重载赋值运算符:基类的对应函数不会自动成为派生类的同签名函数。派生类的默认拷贝/赋值函数会自动调用基类的对应函数,但这是编译器生成的派生类专属版本的逻辑,不是继承的产物。

二、为什么可以通过B类对象调用基类A的析构

你能调用b1.~A()和「析构是否被继承」完全是两个逻辑:
公有继承的前提下,基类的公有成员都属于派生类的可查找作用域范围,你显式指定了调用A作用域下的析构函数,编译器只要能找到对应的作用域就允许调用,这不代表~A()是B继承来的成员。如果析构真的被继承,那B自身的析构函数签名应该是~A(),但显然B自己的析构是~B(),二者是完全独立的两个函数。

三、示例代码输出解释

你给出的代码三行输出的触发逻辑依次是:

  1. 第一行dctorA:你手动调用b1.~A()触发基类析构逻辑输出,注意这次调用只会执行析构函数内的打印逻辑,不会释放b1的内存。
  2. 第二行dctorB:main函数结束时,栈上的b1对象生命周期结束,优先调用派生类B的析构函数输出。
  3. 第三行dctorA:B的析构函数执行完成后,编译器自动插入基类A的析构调用,再次执行打印逻辑。

注意:该示例中因为A没有申请堆资源,所以两次调用A的析构没有触发崩溃,但如果A内有动态分配的内存,重复析构会导致双重释放,属于未定义行为,实际开发中禁止手动调用栈对象的析构函数。

内容的提问来源于stack exchange,提问作者Abhishek Mane

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.14 08:54:00