C++类和对象之初始化列表的使用方式

2025-05-13 01:50

本文主要是介绍C++类和对象之初始化列表的使用方式,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

《C++类和对象之初始化列表的使用方式》:本文主要介绍C++类和对象之初始化列表的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教...

C++初始化列表详解:性能优化与正确实践

在C++编程中,初始化列表是构造函数的重要组成部分,它不仅能提升代码性能,还能确保成员变量被正确初始化。本文将深入探讨初始化列表的语法、应用场景及最佳实践。

什么是初始化列表?

初始化列表是构造函数的一部分,用于在对象创建android时直接初始化成员变量。

它位于构造函数参数列表之后,函数体之前,使用冒号(:)和逗号(,)分隔各成员的初始化操作。

class MyClass {
private:
    int value;
    std::string name;
    const double pi;
    int& ref;

public:
    // 使用初始化列表的构造函数
    MyClass(int val, chttp://www.chinasem.cnonst std::string& nm, int& r)
        : value(val), name(nm), pi(3.14159), ref(r) {
        // 构造函数体
    }
};

初始化列表的三大核心作用

1. 性能优化:避免不必要的赋值操作

对于非基本类型(如std::stringstd::vector),初始化列表可以直RZBEVhfS接调用其构造函数,而不是先默认构造再赋值。

对比示例:

// 使用初始化列表(高效)
class A {
public:
    A(const std::string& str) : data(str) {} // 直接构造
private:
    std::string data;
};

// 使用赋值(低效)
class B {
public:
    B(const std::string& str) { data = str; } // 默认构造 + 赋值
private:
    std::string data;
};

2. 强制初始化:处理const和引用成员

const成员和引用必须在初始化时赋值,初始化列表是唯一的方式。

class Config {
private:
    const int maxSize;      // 常量成员
    std::string& filePath;  // 引用成员

public:
    Config(int size, std::string& path) 
        : maxSize(size), filePath(path) {} // 必须在初始化列表中赋值
};

3. 基类初始化:正确调用父类构造函数

当基类没有默认构造函数时,必须通过初始化列表显式调用其带参构造函数。

class Base {
public:
    Base(int value) { /* ... */ }
};

class Derived : public Base {
public:
    Derived(int x) : Base(x) { /* ... */ } // 调用基类构造函数
};

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

在C++中,引用、const成员变量以及没有默认构造函数的类类型成员变量必须在构造函数初始化列表中进行初始化,这是由它们的语义和C++对象生命周期的规则决定的。

1. 引用(Reference)

引用的本质是对象的别名,一旦绑定到某个对象就无法重新绑定。因此:

  • 必须在创建时初始化:引用没有“未初始化”状态,必须在定义时指定其引用的对象。
  • 构造函数体执行前成员已初始化:构造函数体中的代码执行时,成员变量已经完成初始化。若在构造函数体内对引用赋值,实际上是对已初始化的引用进行赋值操作(改变被引用对象的值),而非初始化引用本身。

示例:

class Example {
private:
    int& ref;  // 引用必须初始化
public:
    Example(int& value) : ref(value) {}  // 正确:初始化列表中初始化
};

2. const 成员变量

const成员变量的值在对象的生命周期内不可修改,因此:

  • 必须在初始化时赋值const变量一旦初始化就不能再被赋值。
  • 初始化列表是唯一机会:构造函数体执行前,const成员必须已经被赋予初始值。

示例:

class Example {
private:
    const int value;  // const成员必须初始化
public:
    Example(int val) : value(val) {}  // 正确:初始化列表中初始化
};

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

如果一个类没有默认构造函数(即没有无参构造函数),则在创建该类的对象时必须显式提供参数。因此:

  • 必须通过参数初始化:编译器无法默认构造该成员,必须显式调用其带参构造函数。
  • 初始化列表提供了显式调用的机会:在初始化列表中,可以指定参数来调用成员的带参构造函数。

示例:

class Inner {
public:
    Inner(int x) {}  // 只有带参构造函数
};

class Example {
private:
    Inner inner;  // Inner没有默认构造函数
public:
    Example(int x) : inner(x) {}  // 正确:显式调用Inner的带参构造函数
};

为什么不能在构造函数体中初始化?

构造函数体中的代码执行时,成员变量已经完成初始化(默认初始化或编译器生成的初始化)。因此:

  • 引用和const成员:无法在构造函数体中重新初始化,因为它们必须在初始化时就确定值。
  • 无默认构造函数的类成员:如果未在初始化列表中显式构造,编译器会尝试调用其默认构造函数,但由于该类没有默认构造函数,会导致编译错误。

初始化列表的作用是在对象的内存分配后、构造函数体执行前,显式控制成员变量的初始化过程。对于引用、const成员和无默认构造函数的类成员,初始化列表是唯一能满足其初始化语义的地方。若不使用初始化列表,代码将因“未初始化的引用/const成员”或“无法默认构造的类成员”而编译失败。

初始化列表的语法规则

1. 初始化顺序由声明顺序决定

成员变量的初始化顺序由其在类中声明的顺序决定,而非初始化列表中的顺序。错误的顺序可能导致未定义行为。

class Example {
private:
    int a;
    int b;

public:
    // 危险:初始化列表顺序与声明顺序不一致
    Example(int value) : b(value), a(b) {} // a先被初始化,但此时b未初始化
};

2. 支持表达式初始化

可以使用常量、函数返回值或其他成员变量进行初始化。

class Point {
private:
    int x;
python    int y;
    int distance;

public:
    Point(int _x, int _y) 
        : x(_x), y(_y), 
          distance(calculaandroidteDistance(_x, _y)) {} // 使用函数返回值初始化

    int calculateDistance(int x, int y) const {
        return std::sqrt(x*x + y*y);
    }
};

初始化列表 vs 构造函数体赋值

特性初始化列表构造函数体赋值
执行时机对象创建时对象创建后
性能通常更高效可能涉及额外的赋值操作
const/引用成员支持不支持
基类初始化必须使用不可用

总结

初始化列表总结:

  • 无论是否显⽰写初始化列表,每个构造函数都有初始化列表;
  • 无论是否在初始化列表显⽰初始化成员变量,每个成员变量都要⾛初始化列表初始化;

C++类和对象之初始化列表的使用方式

以上为个人经验,希望能给大家一个参考,也希望大家多多支持China编程(www.chinasem.cn)。

这篇关于C++类和对象之初始化列表的使用方式的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1154587

相关文章

java实现docker镜像上传到harbor仓库的方式

《java实现docker镜像上传到harbor仓库的方式》:本文主要介绍java实现docker镜像上传到harbor仓库的方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录1. 前 言2. 编写工具类2.1 引入依赖包2.2 使用当前服务器的docker环境推送镜像2.2

C++20管道运算符的实现示例

《C++20管道运算符的实现示例》本文简要介绍C++20管道运算符的使用与实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录标准库的管道运算符使用自己实现类似的管道运算符我们不打算介绍太多,因为它实际属于c++20最为重要的

Visual Studio 2022 编译C++20代码的图文步骤

《VisualStudio2022编译C++20代码的图文步骤》在VisualStudio中启用C++20import功能,需设置语言标准为ISOC++20,开启扫描源查找模块依赖及实验性标... 默认创建Visual Studio桌面控制台项目代码包含C++20的import方法。右键项目的属性:

Go语言数据库编程GORM 的基本使用详解

《Go语言数据库编程GORM的基本使用详解》GORM是Go语言流行的ORM框架,封装database/sql,支持自动迁移、关联、事务等,提供CRUD、条件查询、钩子函数、日志等功能,简化数据库操作... 目录一、安装与初始化1. 安装 GORM 及数据库驱动2. 建立数据库连接二、定义模型结构体三、自动迁

ModelMapper基本使用和常见场景示例详解

《ModelMapper基本使用和常见场景示例详解》ModelMapper是Java对象映射库,支持自动映射、自定义规则、集合转换及高级配置(如匹配策略、转换器),可集成SpringBoot,减少样板... 目录1. 添加依赖2. 基本用法示例:简单对象映射3. 自定义映射规则4. 集合映射5. 高级配置匹

Spring 框架之Springfox使用详解

《Spring框架之Springfox使用详解》Springfox是Spring框架的API文档工具,集成Swagger规范,自动生成文档并支持多语言/版本,模块化设计便于扩展,但存在版本兼容性、性... 目录核心功能工作原理模块化设计使用示例注意事项优缺点优点缺点总结适用场景建议总结Springfox 是

嵌入式数据库SQLite 3配置使用讲解

《嵌入式数据库SQLite3配置使用讲解》本文强调嵌入式项目中SQLite3数据库的重要性,因其零配置、轻量级、跨平台及事务处理特性,可保障数据溯源与责任明确,详细讲解安装配置、基础语法及SQLit... 目录0、惨痛教训1、SQLite3环境配置(1)、下载安装SQLite库(2)、解压下载的文件(3)、

使用Python绘制3D堆叠条形图全解析

《使用Python绘制3D堆叠条形图全解析》在数据可视化的工具箱里,3D图表总能带来眼前一亮的效果,本文就来和大家聊聊如何使用Python实现绘制3D堆叠条形图,感兴趣的小伙伴可以了解下... 目录为什么选择 3D 堆叠条形图代码实现:从数据到 3D 世界的搭建核心代码逐行解析细节优化应用场景:3D 堆叠图

c++中的set容器介绍及操作大全

《c++中的set容器介绍及操作大全》:本文主要介绍c++中的set容器介绍及操作大全,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录​​一、核心特性​​️ ​​二、基本操作​​​​1. 初始化与赋值​​​​2. 增删查操作​​​​3. 遍历方

解析C++11 static_assert及与Boost库的关联从入门到精通

《解析C++11static_assert及与Boost库的关联从入门到精通》static_assert是C++中强大的编译时验证工具,它能够在编译阶段拦截不符合预期的类型或值,增强代码的健壮性,通... 目录一、背景知识:传统断言方法的局限性1.1 assert宏1.2 #error指令1.3 第三方解决