C++特殊成员函数不被继承的含义及子类调用父类析构疑问
问题解答
一、「构造函数、析构函数、重载赋值运算符、拷贝构造函数不被继承」的准确含义
首先明确C++中「成员被继承」的判定标准:如果基类的某成员被派生类继承,那么派生类将原生拥有该签名的成员作为自身成员,无需额外声明即可直接作为自身接口使用。
上述特殊成员不被继承,具体指:
- 构造函数:基类的构造函数不会自动成为派生类的构造函数。比如基类
A有构造函数A(int, double),派生类B默认不会自动生成B(int, double),除非你显式定义派生类构造函数,或者用using A::A;显式把基类构造引入派生类作用域。 - 析构函数:派生类的析构函数是独立于基类的专属成员,不会复用基类的析构签名。派生类析构执行完成后会自动调用基类析构,但这是编译器插入的调用逻辑,不代表析构是继承来的。
- 拷贝构造、重载赋值运算符:基类的对应函数不会自动成为派生类的同签名函数。派生类的默认拷贝/赋值函数会自动调用基类的对应函数,但这是编译器生成的派生类专属版本的逻辑,不是继承的产物。
二、为什么可以通过B类对象调用基类A的析构
你能调用b1.~A()和「析构是否被继承」完全是两个逻辑:
公有继承的前提下,基类的公有成员都属于派生类的可查找作用域范围,你显式指定了调用A作用域下的析构函数,编译器只要能找到对应的作用域就允许调用,这不代表~A()是B继承来的成员。如果析构真的被继承,那B自身的析构函数签名应该是~A(),但显然B自己的析构是~B(),二者是完全独立的两个函数。
三、示例代码输出解释
你给出的代码三行输出的触发逻辑依次是:
- 第一行
dctorA:你手动调用b1.~A()触发基类析构逻辑输出,注意这次调用只会执行析构函数内的打印逻辑,不会释放b1的内存。 - 第二行
dctorB:main函数结束时,栈上的b1对象生命周期结束,优先调用派生类B的析构函数输出。 - 第三行
dctorA:B的析构函数执行完成后,编译器自动插入基类A的析构调用,再次执行打印逻辑。
注意:该示例中因为
A没有申请堆资源,所以两次调用A的析构没有触发崩溃,但如果A内有动态分配的内存,重复析构会导致双重释放,属于未定义行为,实际开发中禁止手动调用栈对象的析构函数。
内容的提问来源于stack exchange,提问作者Abhishek Mane
相关产品推荐
相关产品推荐

