学习记录:C++初始化列表使用

在 C++ 中,构造函数后面的冒号 : 引出的部分就是 初始化列表。它用于在构造函数体执行之前初始化类的成员变量。使用初始化列表有以下几个主要好处:

1. 提高效率,避免默认构造再赋值

如果不使用初始化列表,编译器会首先使用默认构造函数来构造成员变量,然后在构造函数体内进行赋值操作。这种做法可能导致不必要的操作,特别是在成员变量类型比较复杂时,比如自定义类型或者引用类型等。初始化列表直接在成员变量构造时就进行初始化,避免了重复构造和赋值的开销。

例如:

class MyClass {
private:
    std::string name;
    int age;
public:
    MyClass(const std::string& name, int age) {
        this->name = name;   // 先默认构造,再赋值
        this->age = age;
    }
};

如果改用初始化列表:

class MyClass {
private:
    std::string name;
    int age;
public:
    MyClass(const std::string& name, int age) : name(name), age(age)  // 直接初始化
    {}
};

在这种情况下,nameage 会直接通过初始化列表进行初始化,而不是先默认构造再赋值。

2. 初始化常量成员

C++ 中的常量成员变量(const)必须在构造函数的初始化列表中初始化,而不能在构造函数体内进行赋值。如果没有在初始化列表中初始化常量成员,编译器会报错。

例如:

class MyClass {
private:
    const int id;
public:
    MyClass(int id) : id(id) {}  // 必须在初始化列表中初始化常量成员
};

如果将常量成员初始化放到构造函数体内,会导致编译错误:

class MyClass {
private:
    const int id;
public:
    MyClass(int id) {
        this->id = id;  // 错误,const 成员不能被赋值
    }
};

3. 初始化引用成员

引用类型成员变量必须通过初始化列表进行初始化,因为引用在 C++ 中必须在构造时绑定到一个对象,而不能通过赋值来重新绑定。因此,引用成员必须在初始化列表中初始化。

例如:

class MyClass {
private:
    int& ref;
public:
    MyClass(int& ref) : ref(ref) {}  // 必须在初始化列表中初始化引用成员
};

如果尝试在构造函数体内给引用成员赋值,会导致编译错误:

class MyClass {
private:
    int& ref;
public:
    MyClass(int& ref) {
        this->ref = ref;  // 错误,引用成员不能重新绑定
    }
};

4. 对基类的初始化

当一个类有基类时,基类的构造函数也需要在初始化列表中显式调用,否则基类的默认构造函数会在构造函数体执行前被调用。如果基类没有默认构造函数,编译器会要求显式调用基类的构造函数。

例如:

class Base {
public:
    Base(int x) {
        // 基类的构造函数
    }
};
class Derived : public Base {
public:
    Derived(int x, int y) : Base(x) {
        // 子类构造函数
    }
};

如果没有显式在初始化列表中调用 Base(x),编译器将尝试调用基类的默认构造函数(如果有的话),如果没有默认构造函数,会导致编译错误。

5. 初始化复杂类型(如 STL 容器)

STL 容器类、智能指针等较为复杂的类型最好在初始化列表中进行初始化,因为这些类型的成员往往会涉及到内存分配或其他初始化操作,使用初始化列表比在构造函数体内初始化更加高效。

例如:

#include <vector>

class MyClass {
private:
    std::vector<int> data;
public:
    MyClass(const std::vector<int>& init_data) : data(init_data) {}  // 高效初始化
};

如果不使用初始化列表,可能需要先构造一个空的 vector,然后再将传入的值赋值给它。

特别注意:初始化顺序

成员变量的初始化顺序是按照它们在类定义中声明的顺序,而不是在初始化列表中的顺序。因此,使用初始化列表时,可以清楚地控制成员变量的初始化顺序,避免意外的初始化顺序错误。

class MyClass {
private:
    int a;
    int b;
public:
    MyClass(int x, int y) : b(y), a(x) {}  // a 会先初始化,b 后初始化
};

即使 b 在初始化列表中排在 a 之前,a 依然会在 b 之前被初始化,因为成员变量的初始化顺序由它们在类中声明的顺序决定。


总结

使用 初始化列表 在 C++ 中有很多好处,尤其是在性能和语义上。它能够提高效率,减少不必要的默认构造与赋值操作;同时,它是初始化常量、引用成员以及基类成员的唯一方式;并且它还能保证成员变量按照声明的顺序进行初始化。通过合理使用初始化列表,能够编写出更高效、更安全、更可维护的代码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值