C++构造函数初始化列表

一. 何为构造函数初始化列表

class Sample {
public:
    // 构造函数内部赋值
    Sample(int a)  {
        a_ = a;
    }

    // 构造函数初始化列表
    Sample(int a) : a_(a) {

    }
private:
    int a_;
};

上面的代码中,Sample类的2个构造函数的功能是一样的,都是初始化成员变量a_,区别在于一个采用的是构造函数内部赋值的方式来初始化的,另一个采用的是构造函数初始化列表初始化列表的方式来初始化的。


二. 何时必须使用初始化列表

如果按照上面所说的,既然2种初始化成员变量的方式所起得作用是一样的,那么在哪些情况下必须使用构造函数初始化列表的了?
下面2种情况的成员变量必须使用构造函数初始化列表的方式来初始化:

  1. 成员变量是const常量。
  2. 成员变量是引用类型。

下面例子演示了成员变量是const常量引用类型时,如何初始化它们:

class Sample {
public:
    Sample() : kCount(11), name_(std::string("jeff"))  {

    }
private:
    std::string &name_;
    const int kCount;
};

三. 初始化列表的顺序问题

使用构造函数初始化列表进行成员变量初始化时,要注意成员变量的初始化顺序。
举个例子来说明,现有类SeqSample有3个成员变量a_, b_, c_,构造函数被设计为将a_, b_, c_都初始化为m,也就是a_ == b_ == c_ == m

class SeqSample {
public:
    SeqSample(int m) : 
        a_(m), 
        b_(a_), 
        c_(b_) 
    {

    }

private:
    int b_;
    int a_;
    int c_;
};

int main()
{
    SeqSample ss(1);
    return 0;
}

通过调试器观察到执行构造函数初始化之后,成员变量a_, b_, c_的值分别为:

b_ = -858993460
a_ = 1
c_ = -858993460

而不是我们期望的a_ = 1 b_ = 1 c_ = 1

出现这种问题的原因在于:编译器对构造函数初始化列表中的变量进行初始化的时候,不是按照变量初始化列表中的顺序来进行初始化的,而是按照变量在类中的声明顺序来初始化的。

所以,在初始化列表中的变量有依赖关系时(如上面的b_依赖于a_的初始化结果),要特别注意这种情况。


四. 初始化列表的另一个好处

先模糊的把这个好处说出来,不太明白的,可以看下面的示例:
若成员变量是类对象,则使用构造函数的初始化列表可以减少一次默认构造函数的调用。

测试代码如下(声明了一个Apple类,一个Test类,Test类中有2个Apple对象apple1_, apple2_,唯一不同的是,apple1_通过初始化列表来初始化,apple2_通过函数体中的赋值语句来初始化):

class Apple {
public:
    Apple() {
        printf("默认构造函数\n");
    }

    Apple(const Apple &that) {
        printf("复制构造函数\n");
    }

    Apple& operator = (const Apple&that) {
        printf("赋值运算符重载\n");
        return *this;
    }
};

class Test {
public:
    Test(const Apple &apple) : apple1_(apple) {
        apple2_ = apple;
    }
private:
    Apple apple1_;
    Apple apple2_;
};


int main()
{
    Apple apple;
    Test t(apple);
    return 0;
}

运行结果如图:
这里写图片描述

4行输出分别由不同的语句产生,如图:
这里写图片描述

apple1_(apple)直接执行的复制构造函数,所以只产生一行输出;
apple2_ = apple;却是先使用默认构造函数构造了一个apple2_对象,然后再通过赋值运算符将apple的内容更新到apple2_中,所以产生了2行输出。

五. 构造函数初始化列表的异常捕获

构造的函数的初始化列表也可以使用异常捕获,具体使用方式如下:

class Foo {
public:
    Foo::Foo(int n)
        try :size(n), array(new int[n]) {
        //...  
    }
    catch (const std::bad_alloc& e) {
        printf("%s\n", e.what());
    }
private:
    int size;
    int *array;
};
  • 5
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

china_jeffery

你的鼓励是我前进的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值