c++构造函数的初始化列表

本文介绍了C++中构造函数的初始化列表的概念及其重要性。文章详细解释了使用初始化列表的两种主要场景:必要性和效率考量,并通过实例展示了在特定情况下如何正确应用初始化列表。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

与其他函数不同,构造函数除了有名字,参数列表和函数体之外,还可以有初始化列表,初始化列表以冒号开头,后跟一系列以逗号分隔的初始化字段。
例如:

struct foo
{
    string name ;
    int id ;
    foo(string s, int i):name(s), id(i){} ; // 初始化列表
};

初始化类的成员有两种方式,一是使用初始化列表,二是在构造函数体内进行赋值操作。使用初始化列表主要是基于性能问题,对于内置类型,如int, float等,使用初始化类表和在构造函数体内初始化差别不是很大,但是对于类类型来说,最好使用初始化列表,使用初始化列表少了一次调用默认构造函数的过程,这对于数据密集型的类来说,是非常高效的。
综上,使用初始化列表有两个原因:
原因1.必须这样做:
《C++ Primer》中提到在以下三种情况下需要使用初始化成员列表:
情况一、类成员为没有默认构造函数的类类型
情况二、const修饰的类成员引用成员数据;
情况三、子类初始化父类的私有成员; 如果类存在继承关系,派生类必须在其初始化列表中调用基类的构造函数

对于情况一的说明:数据成员是对象,并且这个对象只有含参数的构造函数,没有无参数的构造函数;
如果我们有一个类成员,它本身是一个类或者是一个结构,而且这个成员它只有一个带参数的构造函数,而没有默认构造函数,这时要对这个类成员进行初始化,就必须调用这个类成员的带参数的构造函数,如果没有初始化列表,那么他将无法完成第一步,就会报错。
看一个例子:

struct Test1
{
    Test1() // 无参构造函数
    { 
        cout << "Construct Test1" << endl ;
    }

    Test1(const Test1& t1) // 拷贝构造函数
    {
        cout << "Copy constructor for Test1" << endl ;
        this->a = t1.a ;
    }

    Test1& operator = (const Test1& t1) // 赋值运算符
    {
        cout << "assignment for Test1" << endl ;
        this->a = t1.a ;
        return *this;
    }

    int a ;
};

struct Test2
{
    Test1 test1 ;
    Test2(Test1 &t1)
    {
        test1 = t1 ;
    }
};
int main()
{
    Test1 t1 ;
    Test2 t2(t1) ;
    return 0;
}

输出:
这里写图片描述

第一行输出对应调用代码中第一行,构造一个Test1对象。第二行输出对应Test2构造函数中的代码,用默认的构造函数初始化对象test1,这就是所谓的初始化阶段。第三行输出对应Test1的赋值运算符,对test1执行赋值操作,这就是所谓的计算阶段。
对于这个例子,如果Test2中使用初始化列表:

struct Test2
{
    Test1 test1 ;
    Test2(Test1 &t1):test1(t1){}
}

输出如下:
这里写图片描述
这种形式来初始化test1,那么调用的时候就会直接使用test1的拷贝构造函数,而不会是先调用无参构造函数再对其进行赋值操作了,这于数据密集型的类来说,是非常高效的。
原因2.效率要求这样做:
类对象的构造顺序显示,进入构造函数体后,进行的是计算,是对成员变量的赋值操作,显然,赋值和初始化是不同的,这样就体现出了效率差异,如果不用成员初始化类表,那么类对自己的类成员分别进行的是一次隐式的默认构造函数的调用,和一次赋值操作符的调用,如果是类对象,这样做效率就得不到保障。
注意:构造函数需要初始化的数据成员,不论是否显示的出现在构造函数的成员初始化列表中,都会在该处完成初始化,并且初始化的顺序和其在类中声明时的顺序是一致的,与列表的先后顺序无关,所以要特别注意,保证两者顺序一致才能真正保证其效率和准确性。

注意:
1、构造函数列表的初始化方式不是按照列表的的顺序,而是按照变量声明的顺序。所以,一个好的习惯是,按照成员定义的顺序进行初始化。
2、在子类中,只有初始化列表可以构造父类的private成员(通过显示调用父类的构造函数)。
3、一个好的原则是,能使用初始化列表的时候尽量使用初始化列表。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值