C++ 对象——对象之成员初始化列表

embedded/2024/9/23 22:55:29/

C++ 对象——成员初始化列表

    • 1. 什么是成员初始化列表
    • 2. 何时必须使用成员初始化列表
      • 2.1 引用类型成员变量
      • 2.2 const 类型成员变量
      • 2.3 继承自基类的类
      • 2.4 带参数的类类型成员变量
      • 2.5 使用基类的特定构造函数
      • 2.6 初始化复杂类型
      • 2.7 避免隐式转换
    • 3. 使用初始化列表的优势
      • 3.1 性能优化
      • 3.2 清晰性
      • 3.3 避免不必要的构造
    • 4. 初始化列表的细节探究
      • 4.1 编译器处理
      • 4.2 执行顺序
      • 4.3 成员变量的类型
      • 4.4 初始化列表的使用
    • 5. 常见错误
      • 5.1 使用未初始化的变量
      • 5.2 忘记调用基类构造函数
      • 5.3 初始化顺序混淆
      • 5.4 忘记初始化 const 成员
      • 5.5 使用不适当的类型转换
    • 总结

1. 什么是成员初始化列表

成员初始化列表是在构造函数中用于初始化类成员的语法。它在构造函数体执行之前初始化成员变量。

ClassName::ClassName(parameters) : member1(value1), member2(value2) {// 构造函数体
}

2. 何时必须使用成员初始化列表

2.1 引用类型成员变量

class Example {
private:int& ref;public:Example(int& r) : ref(r) {} // 必须在初始化列表中初始化
};

解释:引用类型成员变量必须在对象创建时绑定到一个有效的引用,不能在构造函数体中赋值。

2.2 const 类型成员变量

class Example {
private:const int value;public:Example(int v) : value(v) {} // 必须在初始化列表中初始化
};

解释const 成员变量必须在构造时赋值,无法在构造函数体内修改,并且在对象生命周期内不能被修改。

2.3 继承自基类的类

class Base {
public:Base(int x) {}
};class Derived : public Base {
public:Derived(int x) : Base(x) {} // 必须在初始化列表中调用基类构造函数
};

解释:如果基类有构造函数,子类必须在初始化列表中调用。如果基类没有默认构造函数,子类构造函数必须调用基类的构造函数。

2.4 带参数的类类型成员变量

class MyClass {
private:std::string name;public:MyClass(const std::string& n) : name(n) {} // 使用初始化列表
};

解释:如果成员变量的类型是某个类类型且构造函数带有参数,必须使用初始化列表。使用初始化列表可以避免不必要的构造和析构。

2.5 使用基类的特定构造函数

class Base {
public:Base(int x) {}Base(double y) {}
};class Derived : public Base {
public:Derived(int x) : Base(x) {} // 调用特定的基类构造函数
};

解释:当基类有多个构造函数时,子类需要通过初始化列表调用特定的构造函数,参数的类型必须匹配。

2.6 初始化复杂类型

#include <vector>class Example {
private:std::vector<int> data;public:Example() : data(10, 0) {} // 初始化列表直接初始化容器
};

解释:对于 STL 容器等复杂类型,使用初始化列表可以避免默认构造后再赋值,并且可以更高效地分配内存。

2.7 避免隐式转换

class Example {
private:double value;public:Example(int v) : value(v) {} // 避免隐式转换
};

解释:当构造函数参数类型与成员变量类型不匹配时,使用初始化列表可以避免隐式转换的问题,隐式转换可能导致潜在错误。


3. 使用初始化列表的优势

3.1 性能优化

class Example {
private:std::string name;public:Example(const std::string& n) : name(n) {} // 直接初始化
};

解释:直接初始化成员变量,避免了默认构造和随后的赋值,提升性能,尤其对于大型对象,避免不必要的复制构造。

3.2 清晰性

class Example {
private:int x;double y;public:Example(int a, double b) : x(a), y(b) {} // 初始化列表清晰明了
};

解释:使用初始化列表使构造函数的意图更加明确,易于阅读和维护,能更好地表达对象的状态。

3.3 避免不必要的构造

class Example {
private:std::vector<int> vec;public:Example() : vec(10, 0) {} // 直接初始化,避免默认构造
};

解释:使用初始化列表可以避免不必要的构造和销毁,减少资源浪费,这在资源管理(如内存、文件句柄等)方面尤为重要。


4. 初始化列表的细节探究

4.1 编译器处理

class Example {
private:int a;int b;public:Example(int x, int y) : a(x), b(y) {} // 编译器在构造函数开头处理
};

解释:初始化列表中的代码在编译时被处理,实际上在构造函数的开头执行,编译器在生成代码时会考虑初始化列表的内容。

4.2 执行顺序

class Example {
private:int a;int b;public:Example(int x, int y) : b(y), a(x) {} // a 在 b 之前定义,但在 b 之后初始化
};

解释:成员变量的初始化顺序按照它们在类定义中的顺序,而不是初始化列表中的顺序,这一点对于理解对象的状态很重要。

4.3 成员变量的类型

class Complex {
private:std::string str;public:Complex(const char* s) : str(s) {} // 必须使用初始化列表
};

解释:某些成员变量类型(如具有参数的构造函数)必须使用初始化列表进行初始化,使用初始化列表可以避免额外的内存分配。

4.4 初始化列表的使用

class Base {
public:Base(int x) {}
};class Derived : public Base {
public:Derived(int x) : Base(x) {} // 使用初始化列表调用基类构造函数
};

解释:可以在初始化列表中进行成员变量的初始化、基类的构造调用以及调用其他构造函数(如委托构造)。


5. 常见错误

5.1 使用未初始化的变量

class Example {
private:int value;public:Example(int v) : value(v + someUndefinedVariable) {} // 错误:someUndefinedVariable 未定义
};

解释:在初始化列表中使用未定义的变量会导致编译错误或未定义行为。确保所有变量在使用前已正确定义和初始化。

5.2 忘记调用基类构造函数

class Base {
public:Base(int x) {}
};class Derived : public Base {
public:Derived(int x) {} // 错误:未调用 Base 的构造函数
};

解释:如果基类没有默认构造函数,子类必须在初始化列表中调用基类的构造函数,否则会导致编译错误。

5.3 初始化顺序混淆

class Example {
private:int a;int b;public:Example(int x, int y) : b(y), a(x) {} // 正确,但 a 在构造时先于 b 初始化
};

解释:成员变量的初始化顺序是按照它们在类中声明的顺序,而不是初始化列表中的顺序。理解这一点可以避免潜在的问题。

5.4 忘记初始化 const 成员

class Example {
private:const int value;public:Example() {} // 错误:未初始化 const 成员
};

解释const 成员变量必须在初始化列表中初始化,忘记将导致编译错误。

5.5 使用不适当的类型转换

class Example {
private:double value;public:Example(int v) : value(v) {} // 可能导致隐式转换
};

解释:如果构造函数参数和成员变量类型不同,可能会发生隐式转换,导致意外的行为。使用初始化列表时要小心类型匹配。


总结

使用成员初始化列表在 C++ 中具有多个优势,包括性能优化、清晰性和避免不必要的构造。同时,了解初始化列表的细节也能帮助开发者更好地管理对象的生命周期和资源。


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

相关文章

ollama教程——使用LangChain调用Ollama接口实现ReAct

ollama入门系列教程简介与目录 相关文章: Ollama教程——入门:开启本地大型语言模型开发之旅Ollama教程——模型:如何将模型高效导入到Ollama框架Ollama教程——兼容OpenAI API:高效利用兼容OpenAI的API进行AI项目开发Ollama教程——使用LangChain:Ollama与LangChain的强强…

Nginx 配置Nextjs和SpringBoot项目的https并解决跨域问题

目录 一、Nginx配置文件 二、跨域解决 一、Nginx配置文件 # 禁止ip访问server {ssl_certificate /ssl/xloda.com_cert_chain.pem;ssl_certificate_key /ssl/xloda.com_key.key;ssl_session_cache shared:SSL:1m;ssl_session_timeout 5m;ssl_ciphers HIGH:!aNULL:!…

k8s nginx ingress 开启缓存(cache)的方法

在k8s集群中&#xff0c;我们都是通过ingress的方法对外暴露访问的。对一些静态的资源&#xff0c;我们可以在nginx ingress侧增加缓存&#xff0c;减小后端服务的压力。 1、需要先找到nginx ingress的configmap配置文件&#xff0c;增加http-snippet # configmap.yaml apiVe…

Ubuntu24.04设置国内镜像软件源

参考文章&#xff1a; Ubuntu24.04更换源地址&#xff08;新版源更换方式&#xff09; - 陌路寒暄 一、禁用原来的软件源 Ubuntu24.04 的源地址配置文件发生改变&#xff0c;不再使用以前的 sources.list 文件&#xff0c;升级 24.04 之后&#xff0c;该文件内容变成了一行注…

挖矿木马攻破了服务器

最近被国外的挖矿木马攻破了服务器 根据非法登录&#xff0c;用 #last指令查看登录ip 首先删掉登录主机 #kill -9 pts/0 第二步 #top 看看什么占用cpu高 第三步杀死狂刷CPU的服务 过一分钟后&#xff0c;服务又开始狂刷cpu。 第四步根据pid查到服务地址 #systemctl status…

【Python零基础学习】变量和简单数据类型

文章目录 前言一、Python中常用数据类型二、变量三、字符串title()方法upper()方法lower()方法字符串中使用变量制表符\t和换行符\nlstrip()、rstrip()、strip()removeprefix()removesuffix() 四、数字整数浮点数"_"下划线 总结 前言 本文主要介绍Python中常用的数据…

编译w2k3的时候补丁文件oscdimg.cmd中的oscdimg.exe命令是很重要的

编译w2k3的时候补丁文件oscdimg.cmd&#xff0c;位置为tools/下面 作用是生成iso文件。 泄露的文件中是没有的&#xff0c;是国外的大神打的补丁。 echo off setlocal ENABLEDELAYEDEXPANSION if NOT defined SDXROOT echo Run from a razzle prompt.&goto :eof cd /d %…

四数之和(LeetCode)

题目 给你一个由 n 个整数组成的数组 nums &#xff0c;和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] &#xff08;若两个四元组元素一一对应&#xff0c;则认为两个四元组重复&#xff09;&#xff1a; 0 <…