C++类的初始化列表是怎么一回事?哪些东西必须放在初始化列表中进行初始化,原因是什么?

embedded/2025/2/4 15:34:20/

目录

  • 01-C++类的初始化列表的概要介绍
    • 语法
    • 为什么使用初始化列表?
    • 示例代码
    • 小结
  • 02-初始化列表是写在构造函数的函数体之前的代码的
    • **1. 结构分析**
    • **2. 示例:基类 + 成员变量**
        • **输出**
    • **3. 初始化列表 vs 构造函数体**
      • **(1) 使用初始化列表**
      • **(2) 在构造函数体赋值**
  • 03-必须放在初始化列表中进行初始化的东西
    • 常量成员
    • 引用成员
    • 没有默认构造函数的类成员
    • 类的基类没有默认构造函数

01-C++类的初始化列表的概要介绍

在C++中,类的初始化列表是一个在构造函数体之前用来初始化类成员的机制。它允许你在构造函数的声明部分直接初始化成员变量,而不是在构造函数体内通过赋值的方式。

语法

初始化列表紧跟在构造函数名称之后,用冒号 : 开始,后面跟着成员变量的初始化。每个成员变量通过逗号 , 分隔。

class ClassName {
public:// 构造函数带有初始化列表ClassName(int a, int b) : x(a), y(b) {  // x和y分别通过初始化列表初始化// 其他构造函数体代码(如果有)}private:int x, y;
};

其中x(a)的意思并不是调用名叫x的函数,而是把成员变量x的值初始化a的值。同样,y(b)的意思也并不是调用名叫y的函数,而是把成员变量y的值初始化为b的值。

为什么使用初始化列表?

  1. 提高效率:通过初始化列表可以直接初始化类成员,而不是先调用默认构造函数再进行赋值操作。
  2. 有一些成员变量只能在初始化列表中进行初始化,具体如下:
    ①常量成员和引用成员:常量成员变量和引用成员必须通过初始化列表来初始化,因为它们无法在构造函数体内被赋值。至于为什么,请往后看,我在后面说明了原因。
    ②如果类型为类类型的成员变量【即某个类的实例对象】没有默认构造函数,也需要在初始化列表中进行初始化。关于什么叫默认构造函数,请看我的另一篇博文 [https://blog.csdn.net/wenhao_ir/article/details/145428240]
  3. 如果一个类的基类没有使用默认构造函数,也需要在初始化列表进行初始化。关于什么叫默认构造函数,请看我的另一篇博文 https://blog.csdn.net/wenhao_ir/article/details/145428240

示例代码

#include <iostream>
using namespace std;class Rectangle {
public:// 带有初始化列表的构造函数Rectangle(int l, int w) : length(l), width(w) {// 构造函数体cout << "Rectangle created!" << endl;}// 打印矩形的面积void area() {cout << "Area: " << length * width << endl;}private:int length, width;
};int main() {Rectangle rect(10, 5);  // 创建一个长为10,宽为5的矩形rect.area();  // 打印矩形的面积return 0;
}

关键点:

  1. Rectangle(int l, int w) : length(l), width(w):初始化列表在这里将 lengthwidth 直接初始化为传入的 lw 参数的值。
  2. lengthwidth 是在构造函数体内使用之前就已经初始化了,而不是在函数体内通过赋值。

小结

  • 初始化列表通过冒号 : 开始,直接在构造函数声明中初始化成员变量。
  • 它比在构造函数体内赋值更高效,尤其对于常量成员、引用成员或需要特殊初始化的成员非常有用。

02-初始化列表是写在构造函数的函数体之前的代码的

初始化列表(Initializer List)是写在构造函数的函数体 {} 之前,用于初始化成员变量和基类。它的语法如下:

ClassName::ClassName(参数列表) : 成员变量1(1), 成员变量2(2), 基类() {  // 构造函数体
}

1. 结构分析

class Example {int a;double b;
public:Example(int x, double y)  // 构造函数: a(x), b(y)  // ✅ 初始化列表(在函数体 `{}` 之前){// 构造函数体}
};
  • : a(x), b(y)初始化列表,用来初始化 ab。其中 a(x)的意思并不是调用名叫a的函数,而是把成员变量a的值初始化x的值。同样,b(y)的意思也并不是调用名叫b的函数,而是把成员变量b的值初始化为y的值。

  • {} 内是构造函数体,在初始化列表执行完之后才会运行。


2. 示例:基类 + 成员变量

#include <iostream>class Base {
public:Base(int x) { std::cout << "Base constructor: " << x << "\n"; }
};class Derived : public Base {int a;
public:Derived(int x, int y): Base(x), a(y)  // ✅ 初始化列表{std::cout << "Derived constructor: " << a << "\n";}
};int main() {Derived d(10, 20);
}
输出
Base constructor: 10
Derived constructor: 20

流程

  1. 先执行初始化列表
    • Base(x) 先调用 Base 的构造函数,输出 "Base constructor: 10"
    • a(y) 赋值给成员变量 a即把y的值传递给成员变量a,注意这里不是调用函数名为a的函数。
  2. 然后执行构造函数体 {}
    • 输出 "Derived constructor: 20"

上面代码中类Derived在定义时继续了基类Base,那么请问public Base中public的意思是什么?
答案见:https://blog.csdn.net/wenhao_ir/article/details/145428506


3. 初始化列表 vs 构造函数体

(1) 使用初始化列表

class Example {int x;
public:Example(int value) : x(value) {}  // ✅ 直接初始化
};

(2) 在构造函数体赋值

class Example {int x;
public:Example(int value) { x = value; }  // 在构造函数中赋值,不推荐
};

推荐使用初始化列表,避免在构造函数中赋值,从而提高效率。


03-必须放在初始化列表中进行初始化的东西

常量成员

由于C++规定,所有成员变量必须在对象构造完成前初始化。而常量成员在初始化后不能修改,所以只能用初始化列表进行初始化。例子如下:

   class Test {const int x;public:Test(int val) : x(val) {} // 常量成员x必须用初始化列表进行初始化,否则编译错误};

引用成员

关于引用成员为什么也必须在初始化列表中进行初始化,详情见 https://blog.csdn.net/wenhao_ir/article/details/145422877
其实原因也和常量成员差不多,只是你需要了解下C++的引用成员是怎么回事儿。
例子如下:

   class Test {int& ref; // ref是一个引用类型的成员public:Test(int& r) : ref(r) {} // ref必须用初始化列表进行初始化};

没有默认构造函数的类成员

如果某个成员变量的类型为类类型,即这个成员变量是一个类的对象实例,而这个类又没有默认构造函数,那么也需要在初始化列表中进行初始化。
详情见 https://blog.csdn.net/wenhao_ir/article/details/145428240

类的基类没有默认构造函数

如果一个类的基类没有使用默认构造函数,也需要在初始化列表进行初始化。详情请请看我的另一篇博文 https://blog.csdn.net/wenhao_ir/article/details/145428240


http://www.ppmy.cn/embedded/159503.html

相关文章

Java中的泛型及其用途是什么?

Java中的泛型&#xff08;Generics&#xff09;是Java语言在2004年引入的一项重要特性&#xff0c;用于增强代码的类型安全性和复用性。泛型允许程序员在定义类、接口或方法时指定类型参数&#xff0c;从而实现对不同数据类型的统一操作。本文将详细探讨Java泛型的概念、用途以…

Vue.js组件开发-实现左侧浮动菜单跟随页面滚动

使用 Vue 实现左侧浮动菜单跟随页面滚动 实现步骤 创建 Vue 项目&#xff1a;使用 Vue CLI 创建一个新的 Vue 项目。设计 HTML 结构&#xff1a;包含一个左侧浮动菜单和一个主要内容区域。编写 CSS 样式&#xff1a;设置菜单的初始样式和滚动时的样式。使用 Vue 的生命周期钩…

使用大语言模型在表格化网络安全数据中进行高效异常检测

论文链接 Efficient anomaly detection in tabular cybersecurity data using large language models 论文主要内容 这篇论文介绍了一种基于大语言模型&#xff08;LLMs&#xff09;的创新方法&#xff0c;用于表格网络安全数据中的异常检测&#xff0c;称为“基于引导式提示…

Linux:宏观搭建网络体系

一、计算机网络背景 1、独立模式&#xff1a;计算机之间相互独立 可是这样的话&#xff0c;如果我们想要做协作就必然需要交互数据&#xff0c;就必须得使用U盘进行拷贝&#xff0c;效率很低&#xff0c;所以我们需要网络互联&#xff0c;将计算机连向同一台服务器&#xff0c…

初入机器学习

写在前面 本专栏专门撰写深度学习相关的内容&#xff0c;防止自己遗忘&#xff0c;也为大家提供一些个人的思考 一切仅供参考 概念辨析 深度学习&#xff1a; 本质是建模&#xff0c;将训练得到的模型作为系统的一部分使用侧重于发现样本集中隐含的规律难点是认识并了解模型&…

设计模式Python版 桥接模式

文章目录 前言一、桥接模式二、桥接模式示例三、桥接模式与适配器模式的联用 前言 GOF设计模式分三大类&#xff1a; 创建型模式&#xff1a;关注对象的创建过程&#xff0c;包括单例模式、简单工厂模式、工厂方法模式、抽象工厂模式、原型模式和建造者模式。结构型模式&…

mysql_init和mysql_real_connect的形象化认识

解析总结 1. mysql_init 的作用 mysql_init 用于初始化一个 MYSQL 结构体&#xff0c;为后续数据库连接和操作做准备。该结构体存储连接配置及状态信息&#xff0c;是 MySQL C API 的核心句柄。 示例&#xff1a; MYSQL *conn mysql_init(NULL); // 初始化连接句柄2. mysql_…

openmv的端口被拆分为两个 导致电脑无法访问openmv文件系统解决办法 openmv USB功能改动 openmv驱动被更改如何修复

我之前误打误撞遇到一次&#xff0c;直接把openmv的全部端口删除卸载然后重新插上就会自动重新装上一个openmv端口修复成功&#xff0c;大家可以先试试不行再用下面的方法 全部卸载再重新插拔openmv 要解决OpenMV IDE中出现的两个端口问题&#xff0c;可以尝试以下步骤&#x…