You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基类类型成员变量通过初始化列表初始化时的构造析构顺序疑问

基类/派生类构造与析构调用次数疑问

问题代码

#include <iostream>

using namespace std;

class A {
public:
    A() { cout << "A Con" << endl; }
    virtual ~A() { cout << "A Dec" << endl; }
};
class B : A {
public:
    A a;
    B(A _a) : a(_a) { 
        cout << "B Con" << endl;
    }
    virtual ~B() { cout << "B Dec" << endl; }    
};

int main()
{
    A a;
    B b(a);
}

问题描述

在派生类B中声明了基类A类型的成员变量,运行代码后发现构造函数调用3次,析构函数调用5次。已知第一个构造函数和最后一个析构函数对应main函数中的变量a,但其余调用是怎么回事?为什么析构函数调用次数更多?

个人猜测

A Con -> a in main()
A Con -> b in main() (base class constructor)
B Con -> b in main() (derived class constructor)
A Dec -> temporary value passed in B(A _a) : a(_a), copy constructor is called...
B Dec -> b in main() (derived class destructor)
A Dec -> member variable in B class (A a;)
A Dec -> b in main() (base class destuctor)
A Dec -> a in main()

请问我的猜测是否正确?


你的猜测整体是正确的,不过有个细节需要纠正:B构造函数的形参_a不是临时值,它是函数的局部形参,在B构造函数执行完成后会被销毁。我们把整个流程拆解清楚:

完整调用流程(含隐式调用)

构造阶段(你看到的3次打印对应以下标注的打印项)

  • 执行A a;:调用A的无参构造 → 打印A Con
  • 调用B b(a)时,先将main中的a拷贝给B构造函数的形参_a:调用A的默认拷贝构造(编译器自动生成,无打印)
  • 构造B对象的基类部分:调用A的无参构造 → 打印A Con
  • 构造B的成员变量a:用形参_a拷贝初始化,调用A的默认拷贝构造(无打印)
  • 执行B的构造函数体:打印B Con

你统计的3次构造调用,应该是指这三个带打印的构造(2次A的无参构造+1次B的构造)。

析构阶段(共5次打印,和你的猜测完全对应)

析构顺序和构造完全相反:

  • B构造函数执行完毕,形参_a被销毁:调用A的析构 → 打印A Dec
  • main函数执行到末尾,销毁B对象b:先调用B的析构 → 打印B Dec
  • 销毁B对象的成员变量a:调用A的析构 → 打印A Dec
  • 销毁B对象的基类A部分:调用A的析构 → 打印A Dec
  • 销毁main中的a:调用A的析构 → 打印A Dec

这就是你看到5次析构打印的原因,形参_a的析构是额外的一次,而它对应的拷贝构造因为是编译器生成的默认版本没有打印,所以会出现析构次数看起来比构造打印次数多的情况。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 14:10:20