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

 更新时间:2025年05月12日 09:57:45   作者:zzh_zao  
这篇文章主要介绍了C++类和对象之初始化列表的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

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

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

什么是初始化列表?

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

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

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

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

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

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

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

对比示例:

// 使用初始化列表(高效)
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;
    int y;
    int distance;

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

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

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

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

总结

初始化列表总结:

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

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Opencv 视频读取与写入的实现示例

    Opencv 视频读取与写入的实现示例

    本文将介绍如何使用OpenCV进行视频读写。通过阅读本文,您将了解如何读取视频文件、处理视频帧、写入视频文件等操作,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习吧
    2023-08-08
  • C语言循环结构与时间函数用法实例教程

    C语言循环结构与时间函数用法实例教程

    这篇文章主要介绍了C语言循环结构与时间函数用法,是C语言中非常重要的一个技巧,需要的朋友可以参考下
    2014-08-08
  • C++中list的使用方法及常用list操作总结

    C++中list的使用方法及常用list操作总结

    这篇文章主要介绍了C++中list的使用方法及常用list操作总结的相关资料,需要的朋友可以参考下
    2017-06-06
  • C++中BitSet和Bloom_Filter的实现

    C++中BitSet和Bloom_Filter的实现

    本文主要介绍了C++中BitSet和Bloom_Filter的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2025-02-02
  • C++定时器实现和时间轮介绍

    C++定时器实现和时间轮介绍

    这篇文章主要介绍了C++定时器实现和时间轮介绍,定时器可以由很多种数据结构实现,比如最小堆、红黑树、跳表、甚至数组都可以,其本质都是拿到最小时间的任务,然后取出该任务并执行,更多相关内容介绍,需要的小伙伴可以参考一下
    2022-09-09
  • C语言顺序表的实现代码

    C语言顺序表的实现代码

    这篇文章主要为大家详细介绍了C语言实现顺序表的实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-09-09
  • 详细理解函C语言的函数栈帧

    详细理解函C语言的函数栈帧

    这篇文章主要为大家介绍了C语言的函数栈帧,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助,希望能够给你带来帮助
    2021-11-11
  • C语言 基本语法示例讲解

    C语言 基本语法示例讲解

    本篇文章主要讲解C语言 基本语法,这里提供简单的示例和代码来详细讲解C语言的基本语法,开始学习C语言的朋友可以看一下
    2016-08-08
  • Qt利用QState状态机实现控件互斥操作详解

    Qt利用QState状态机实现控件互斥操作详解

    这篇文章主要为大家详细介绍了Qt如何利用QState状态机实现控件互斥操作,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2022-12-12
  • C++联合体union用法实例详解

    C++联合体union用法实例详解

    这篇文章主要介绍了C++联合体union用法,较为详细的分析了C++中联合体的概念、实用技巧及相关注意事项,需要的朋友可以参考下
    2015-05-05

最新评论