什么是 C++ 中的初始化列表?它的作用是什么?初始化列表和在构造函数体内赋值有什么区别?

定义

在 C++ 中,初始化列表是一种用于在对象创建时初始化其成员变量的语法机制。它主要用在类的构造函数中,位于构造函数的参数列表之后,函数体之前,以一个冒号:开始,后面跟着一系列以逗号分隔的成员变量初始化语句。

例如:

cpp 复制代码
class MyClass {
private:
    int num;
    double value;
public:
    MyClass(int n, double v) : num(n), value(v) {
    }
};

在上述MyClass类的构造函数MyClass(int n, double v)中,num(n), value(v)就是初始化列表。它用于初始化num和value这两个成员变量。

作用

效率提升

对于某些数据类型,如 const 成员变量和引用成员变量,它们必须在初始化的时候被赋值,不能先定义再赋值。使用初始化列表可以确保这些成员变量在对象创建的第一时间就被正确初始化。

例如:

cpp 复制代码
class ConstRefClass {
private:
    const int constNum;
    int& refNum;
public:
    ConstRefClass(int n, int& ref) : constNum(n), refNum(ref) {
    }
};

在这个ConstRefClass类中,constNum是一个 const 成员变量,refNum是一个引用成员变量。通过初始化列表,可以在构造函数调用时就为它们赋值。如果不使用初始化列表,而是在构造函数体中赋值,对于 const 成员变量会导致编译错误,因为 const 变量一旦定义就不能被修改;对于引用成员变量,也不符合引用必须在定义时初始化的规则。

避免多余的默认构造和赋值操作

当类中包含其他类对象作为成员变量时,如果这些成员变量所属的类有自己的构造函数,使用初始化列表可以直接调用合适的构造函数来初始化成员变量,避免先调用默认构造函数创建对象,再通过赋值操作来给成员变量赋值。

例如,假设有一个Point类和一个Rectangle类,Rectangle类包含两个Point类对象作为其左上角和右下角的坐标。

在Rectangle类的构造函数中,通过初始化列表直接调用Point类的构造函数来初始化topLeft和bottomRight,而不是先默认构造Point对象,再通过赋值操作来设置坐标,这样可以提高效率,特别是当Point类的构造函数中有一些复杂的初始化操作时。

初始化列表和在构造函数体内赋值有什么区别?

语法形式

初始化列表:

位于构造函数的参数列表之后,函数体之前,以冒号:开头,后面跟着成员变量的初始化列表,形式为 "成员变量 (初始值)",多个成员变量之间用逗号分隔。例如:

cpp 复制代码
class MyClass {
private:
    int num;
    double value;
public:
    MyClass(int n, double v) : num(n), value(v) {
    }
};

构造函数体内赋值:

在构造函数的函数体内部,通过赋值语句来给成员变量赋值。例如:

cpp 复制代码
class MyClass {
private:
    int num;
    double value;
public:
    MyClass(int n, double v) {
        num = n;
        value = v;
    }
};

初始化时机

初始化列表:

成员变量的初始化是在对象的存储空间被分配之后,构造函数体执行之前完成的。对于 const 成员变量和引用成员变量,初始化列表是初始化它们的唯一合法方式,因为这些类型的变量必须在定义时就初始化。例如:

cpp 复制代码
class ConstRefExample {
private:
    const int constValue;
    int& refValue;
public:
    ConstRefExample(int n, int& ref) : constValue(n), refValue(ref) {
    }
};

构造函数体内赋值:

成员变量的赋值是在构造函数体执行时进行的,此时成员变量已经被初始化(如果没有在初始化列表中初始化,会先调用默认构造函数进行初始化),然后再进行赋值操作。这意味着对于一些不能被重新赋值的类型(如 const 成员变量),在构造函数体内赋值是不合法的。

效率差异

初始化列表:

在某些情况下效率更高。特别是当类中有其他类对象作为成员变量时,如果使用初始化列表,会直接调用成员变量所属类的构造函数进行初始化。这样可以避免先调用默认构造函数创建对象,然后再通过赋值操作来设置值,减少了一次不必要的构造和赋值过程。例如:

cpp 复制代码
class InnerClass {
public:
    InnerClass() {
        // 假设这里有一些复杂的初始化操作
    }
    InnerClass(int value) {
        // 另一种构造函数,假设也有复杂操作
    }
};
class OuterClass {
private:
    InnerClass inner;
public:
    OuterClass() : inner(10) {
    }
};

在OuterClass的构造函数中,通过初始化列表调用InnerClass的有参数构造函数InnerClass(int value)直接初始化inner。如果不使用初始化列表,而是在构造函数体内赋值,就会先调用InnerClass的默认构造函数,然后再执行赋值操作,这可能会涉及到先构造一个临时对象,再进行赋值,然后销毁临时对象等额外的操作。

构造函数体内赋值:

相对来说效率可能较低,因为可能会涉及到先默认构造成员变量,然后再进行赋值的过程。但对于简单的数据类型(如基本数据类型),这种效率差异通常可以忽略不计。例如,对于int类型的成员变量,在初始化列表初始化和在构造函数体内赋值的性能差异几乎没有。

相关推荐
csdndenglu23 分钟前
QT 5.9.2+VTK8.0实现等高线绘制
开发语言·qt
某某23 分钟前
DashBoard安装使用
大数据·开发语言·kubernetes
@Turbo@26 分钟前
【QT】QString& 与QString区别
开发语言·qt
明月看潮生4 小时前
青少年编程与数学 02-020 C#程序设计基础 15课题、异常处理
开发语言·青少年编程·c#·编程与数学
鸽子炖汤4 小时前
LRC and VIP
c++·算法·图论
鑫鑫向栄4 小时前
[蓝桥杯]机器人塔
数据结构·c++·算法·蓝桥杯
你这个代码我看不懂4 小时前
Java项目OOM排查
java·开发语言
暴力求解4 小时前
C语言---动态内存管理、柔性数组
c语言·开发语言·算法
先做个垃圾出来………4 小时前
Python中使用pandas
开发语言·python·pandas
DanmF--4 小时前
C#面向对象实践项目--贪吃蛇
开发语言·游戏·c#·游戏程序