在C++中,成员变量必须在对象构造完成前初始化,但初始化的方式有多种...

news/2025/2/3 8:21:31 标签: c++

在C++中,成员变量必须在对象构造完成前初始化,但初始化的方式可以有多种,具体取决于成员变量的类型和设计需求。以下是C++中成员变量初始化的规则和相关机制:


1. 成员变量必须初始化

  • 如果成员变量是基本类型(如 intdouble 等)类类型,未显式初始化时,它们的值是未定义的(除非是全局或静态变量,会被默认初始化为零值)。
  • 如果成员变量是引用类型常量成员(const,则必须在成员初始化列表中被显式初始化,否则会导致编译错误。
    常量成员必须在成员初始化列表中进行显式初始化的原因是很明显的,因为它一旦初始化完成,它的值就不能被修改了,假如编译器允许它不用被显式初始化,那么它在完成初始化后就有一个不确定的值作为其初始化值,而它一旦完成初始化,那么其值就不能被修改了,所以它就只能永远保持一个不确定的值,这样的常量对于我们是没有任何意义的,所以它必须在成员初始化列表中被显示初始化。
    而至于为什么引用成员也要在成员初始化列表中被显式初始化,详见 https://blog.csdn.net/wenhao_ir/article/details/145422877

2. 初始化的方式

C++提供了多种初始化成员变量的方式:

(1) 默认初始化

  • 如果没有显式初始化,成员变量会使用默认构造函数(如果有)或未定义的值。
  • 例如:
    class MyClass {
        int x; // 未显式初始化,值未定义
    };
    

(2) 成员初始化列表(Member Initializer List)

  • 在构造函数的初始化列表中显式初始化成员变量。
  • 这是推荐的方式,尤其是对于引用类型常量成员没有默认构造函数的类类型成员
  • 例如:
    class MyClass {
    public:
        int x;
        const int y;
        int& z;
        MyClass(int a, int b, int& c) : x(a), y(b), z(c) {} // 使用初始化列表
    };
    

(3) 构造函数体内赋值

  • 在构造函数体内对成员变量赋值。
  • 这种方式其实不是初始化,而是赋值操作。对于常量成员引用成员,详细的原因我在前面已经说明了,本质上就是因为二者一旦被初始化,对于常量成员值就不能被更改了,对于引用成员,与别的变量的绑定关系就不能再修改了。
  • 例如:
    class MyClass {
    public:
        int x;
        MyClass(int a) {
            x = a; // 赋值,不是初始化
        }
    };
    

(4) 默认成员初始化器(C++11 引入)

  • 在类定义中直接为成员变量提供默认值。
  • 例如:
    class MyClass {
    public:
        int x = 10; // 默认初始化
    };
    

3. 必须使用初始化列表的情况

以下成员变量必须在构造函数的初始化列表中初始化:

  • 常量成员(const:因为常量成员一旦初始化后就不能修改。
  • 引用成员:详细的原因见 https://blog.csdn.net/wenhao_ir/article/details/145422877
  • 没有默认构造函数的类类型成员:如果成员是一个类对象,且该类没有使用默认构造函数进行构造,则必须通过初始化列表显式初始化。

例如:

class MyClass {
public:
    const int x;
    int& y;
    MyClass(int a, int& b) : x(a), y(b) {} // 必须使用初始化列表
};

4. 初始化顺序

  • 成员变量的初始化顺序与它们在类中声明的顺序一致,而不是初始化列表中的顺序。
  • 例如:
    class MyClass {
    public:
        int x;
        int y;
        MyClass(int a) : y(a), x(y) {} // x 会先初始化,但 y 还未初始化,导致 x 的值未定义
    };
    

5. 总结

  • 所有成员变量必须在对象构造完成前初始化。
  • 初始化可以通过默认初始化成员初始化列表构造函数体内赋值默认成员初始化器实现,默认成员初始化器是C++11引入的。
  • 对于常量成员引用成员没有使用默认构造函数的类类型成员,必须使用成员初始化列表

http://www.niftyadmin.cn/n/5840640.html

相关文章

UE5 蓝图学习计划 - Day 7:摄像机与视角控制

在游戏开发中,摄像机视角 是玩家与游戏互动的关键环节。Unreal Engine 5 提供了多种方式来设置摄像机,包括第一人称视角、第三人称视角,以及动态跟随摄像机。在本篇文章中,我们将学习如何在角色蓝图中添加摄像机组件,实…

力扣动态规划-18【算法学习day.112】

前言 ###我做这类文章一个重要的目的还是记录自己的学习过程,我的解析也不会做的非常详细,只会提供思路和一些关键点,力扣上的大佬们的题解质量是非常非常高滴!!! 习题 1.下降路径最小和 题目链接:931. …

【Linux系统】信号:信号保存 / 信号处理、内核态 / 用户态、操作系统运行原理(中断)

理解Linux系统内进程信号的整个流程可分为: 信号产生 信号保存 信号处理 上篇文章重点讲解了 信号的产生,本文会讲解信号的保存和信号处理相关的概念和操作: 两种信号默认处理 1、信号处理之忽略 ::signal(2, SIG_IGN); // ignore: 忽略#…

线性数据结构:单向链表

放弃眼高手低,你真正投入学习,会因为找到一个新方法产生成就感,学习不仅是片面的记单词、学高数......只要是提升自己的过程,探索到了未知,就是学习。 目录 一.链表的理解 二.链表的分类(重点理解&#xf…

浅谈知识蒸馏技术

最近爆火的DeepSeek 技术,将知识蒸馏技术运用推到我们面前。今天就简单介绍一下知识蒸馏技术并附上python示例代码。 知识蒸馏(Knowledge Distillation)是一种模型压缩技术,它的核心思想是将一个大型的、复杂的教师模型&#xff0…

小程序设计和开发:如何研究同类型小程序的优点和不足。

一、确定研究目标和范围 明确研究目的 在开始研究同类型小程序之前,首先需要明确研究的目的。是为了改进自己的小程序设计和开发,还是为了了解市场趋势和用户需求?不同的研究目的会影响研究的方法和重点。例如,如果研究目的是为了…

AI智慧社区--Excel表的导入导出

Excel表导入导出的环境配置 1.导入依赖 <dependency><groupId>cn.afterturn</groupId><artifactId>easypoi-spring-boot-starter</artifactId><version>${easypoi.version}</version></dependency>2.配置Excel的导入导出以及…

如何本地部署DeepSeek

第一步&#xff1a;安装ollama https://ollama.com/download 打开官网&#xff0c;选择对应版本 第二步&#xff1a;选择合适的模型 https://ollama.com/ 模型名称中的 1.5B、7B、8B 等数字代表模型的参数量&#xff08;Parameters&#xff09;&#xff0c;其中 B 是英文 B…