C/Cppnote_4_类的成员变量初始化(构造函数)

C++类中成员变量的初始化有两种方式(二选一)

  • 构造函数初始化列表
  • 构造函数体内赋值

对于不同的成员变量情况,我们使用这两种初始化的情况也有不同:

内部数据类型

对于内部类型的成员变量,两种初始化方式基本上没有区别,效率上也不存在多大差异。

  • 类中 const 数据成员、引用数据成员,必须在初始化列表中初始化(常量)。
class ClassName
{
public:
    ClassName(int val_a, int val_b, int ref, int constVal) :  // 初始化列表
    	Val_A(val_a),
    	Val_B(val_b),
    	Ref(ref),
    	ConstVal(constVal)  // 常量只能用初始化列表
    {
        ...	
    }
// ===================或者================================
    ClassName(int val_a, int val_b)  // 函数体内赋值
    {
        Val_A = val_a;
        Val_B = val_b;
        ...
    }
private:
    int Val_A;
    int Val_B;
    int &Ref;
    const int ConstVal;
};

没有提供默认构造函数的类的子类

class Father
{
public:
    Father(int val_a, int val_b) :  // 没有提供无参的constructor
    	Val_A(val_a),
    	Val_B(val_b)
    { ... }
private:
    int Val_A;
    int Val_B;
};

class Son : public Father
{
public:
    // 子类Son初始化时,要先进行父类Father的初始化。
    // 父类Father只提供了含参的constructor的情况下,子类Son要传递相应参数进行初始化,
    // 且在初始化列表里进行:
    Son(int val_a, int val_b, int sonVal): 
        Father(val_a, val_b)
    {
        this->SonVal = sonVal;
    }
private:
    int SonVal;
};

非内部(自定义)数据类型

先定义一个类:Student

class Student
{
public:
    Student(int id = 0)  // 构造函数
    {
        cout << "Student Constructor Called" << std::endl;
        ID = id;
    }
    Student(Student & other)  // 拷贝构造函数
    {
        cout << "Student Copy Construct Called" << std::endl;
        ID = other.ID;
    }
    Student & operator = (Student & other)  // 重载赋值=
    {
        cout << "Student Operator =  Called" << std::endl;
        ID = other.ID;
        return *this;
    }
private:
    int ID;
};

然后我们看看如果另一个类 Deskmate(非继承关系)中,要初始化 Student 对象的情况:

  1. 初始化列表

    class Deskmate
    {
    public:
        Deskmate(Student & studentA, Student & studentB) :
                Student_A(studentA),
                Student_B(studentB)  // 列表初始化
        {
            cout << "Deskmate Constructor Called" << std::endl;
        }
    private:
        Student Student_A;
        Student Student_B;
    };
    
  2. 赋值

    class Deskmate
    {
    public:
        Deskmate(Student & studentA, Student & studentB)
        {
            cout << "Deskmate Constructor Called" << std::endl;
            Student_A = studentA;  // 赋值初始化
            Student_B = studentB;
        }
    private:
        Student Student_A;
        Student Student_B;
    };
    

主函数声明与输出结果:

int main()
{
    Student s1(1), s2(2);
    Deskmate d(s1,s2);
    return 0;
}
  • O: 初始化列表
    • Student Constructor Called
    • Student Constructor Called
    • Student Copy Constructor Called
    • Student Copy Constructor Called
    • Deskmate Constructor Called
  • O: 赋值初始化
    • Student Constructor Called
    • Student Constructor Called
    • Student Constructor Called
    • Student Constructor Called
    • Deskmate Constructor Called
    • Student Operator = Called
    • Student Operator = Called

即使是将 Student 类对象按引用传入,在初始化时仍需要再为 Student_A, Student_B 调用构造函数(如果按值传入,就还要多调用两次复制构造函数)。用列表初始化时直接调用了 复制构造函数;而赋值初始化需要先调用 普通的构造函数,再使用重载的赋值运算符

因此我们有结论:对于非内部类型的成员变量,列表初始化方式效率更高。

Reference

《C++ Primer(第5版)》

https://www.cnblogs.com/vivian187/p/12736988.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值