什么是 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类型的成员变量,在初始化列表初始化和在构造函数体内赋值的性能差异几乎没有。

相关推荐
夏天的味道٥2 小时前
使用 Java 执行 SQL 语句和存储过程
java·开发语言·sql
IT、木易3 小时前
大白话JavaScript实现一个函数,将字符串中的每个单词首字母大写。
开发语言·前端·javascript·ecmascript
Mr.NickJJ4 小时前
JavaScript系列06-深入理解 JavaScript 事件系统:从原生事件到 React 合成事件
开发语言·javascript·react.js
Dream it possible!4 小时前
LeetCode 热题 100_字符串解码(71_394_中等_C++)(栈)
c++·算法·leetcode
Archer1945 小时前
C语言——链表
c语言·开发语言·链表
My Li.5 小时前
c++的介绍
开发语言·c++
功德+n6 小时前
Maven 使用指南:基础 + 进阶 + 高级用法
java·开发语言·maven
达斯维达的大眼睛6 小时前
qt小项目,简单的音乐播放器
开发语言·qt
面会菜.6 小时前
C语言(队列)
c语言·开发语言
香精煎鱼香翅捞饭6 小时前
java通用自研接口限流组件
java·开发语言