【C++】类和对象(3)--初始化列表(再谈构造函数)

目录

一 引入

二 初始化列表概念

三 初始化列表特性

1 引用和const

2 混合使用

3 自定义成员情况

四 初始化列表中的初始化顺序

五 总结


一 引入

构造函数体赋值

class Date
{
public:Date(int year, int month, int day){_year = year;_month = month;_day = day;}
private:int _year;int _month;int _day;
};

虽然上述构造函数调用之后,对象中已经有了一个初始值,但是不能将其称为对对象中成员变量 的初始化,构造函数体中的语句只能将其称为赋初值,而不能称作初始化。因为初始化只能初始 化一次,而构造函数体内可以多次赋值

二 初始化列表概念

初始化列表:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟 一个放在括号中的初始值或表达式。

class Date
{
public://Date(int year, int month, int day)//{//    // 函数体内初始化//    _year = year;//    _month = month;//    _day = day;//}Date(int year, int month, int day):_year(year), _month(month), _day(day){// 初始化列表}void Print(){cout << _year << '/' << _month << '/' << _day << endl;}private:// 声明int _year; int _month;int _day;
};

上面的例子中两个构造函数的结果是一样的。上面的构造函数(使用初始化列表的构造函数)显式的初始化类的成员;而没使用初始化列表的构造函数是对类的成员赋值,并没有进行显式的初始化。

初始化和赋值对内置类型的成员没有什么大的区别,像上面的任一个构造函数都可以。对非内置类型成员变量,为了避免两次构造,推荐使用类构造函数初始化列表。但有的时候必须用带有初始化列表的构造函数

三 初始化列表特性

1. 每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次)

2. 类中包含以下成员,必须放在初始化列表位置进行初始化:

引用成员变量

const成员变量

自定义类型成员(且该类没有默认构造函数时)

总之 这三类不能在函数内部初始化

1 引用和const

class Date{public:Date(int year, int month, int day){// 函数体内初始化_year = year;_month = month;_day = day;int& _ref;//引用 -->errorconst int _n;//const -->error}void Print(){cout << _year << '/' << _month << '/' << _day << endl;}private:// 声明int _year; // 缺省值int _month;int _day;int& _ref;//引用const int _n;//const};

这是为什么?

引用和const只能初始化而不是赋值

之前有讲过,若是我们自己不去实现构造函数的话,类中会默认提供一个构造函数来初始化成员变量,对于【内置类型】的变量不会处理,对【自定义类型】的变量会去调用它的构造函数。那么对于这里的_year, _month, _day, _ref, _n都属于内置类型的数据,所以编译器不会理睬,可是引用变量, const修饰的变量又必须要初始化,所以初始化列表诞生

有人说给个缺省值不就好了 这个办法确实是可以解决我们现在的问题,因为C++11里面为内置类型不初始化打了一个补丁,在声明的位置给到一个初始化值,就可以很好地防止编译器不处理的问题

但是现在我想问一个问题:如果不使用这个办法呢?你有其他方法吗?难道C++11以前就那它没办法了吗?

改正如下:

class Date
{
public://Date(int year, int month, int day)//{//    // 函数体内初始化//    _year = year;//    _month = month;//    _day = day;//     int& _ref;//引用 -->error//     const int _n;//const -->error//}Date(int year, int month, int day):_year(year), _month(month), _day(day), _ref(year), _n(1){// 初始化列表}void Print(){cout << _year << '/' << _month << '/' << _day << endl;}private:// 声明int _year; // 缺省值int _month;int _day;int& _ref;//引用const int _n;//const
};

2 混合使用

当然函数体内初始化和初始化列表可以混着用

Date(int year, int month, int day): _ref(year), _n(1){// 函数体内初始化_year = year;_month = month;_day = day;}

3 自定义成员情况

class A
{
public:A(int a = 0)//默认构造:_a(a){cout << "A(int a = 0)" << endl;}
private:int _a;
};class Date
{
public:Date(int year, int month, int day){// 函数体内初始化_year = year;_month = month;_day = day;}private:// 声明int _year; int _month;int _day;A _aa;//调用默认构造
};int main()
{Date d(2023, 11, 14);return 0;
}

1 如果A没有默认构造呢? -->初始化列表

class A
{
public:A(int a)//这不是默认构造:_a(a){cout << "A(int a = 0)" << endl;}
private:int _a;
};class Date
{
public:Date(int year, int month, int day):_aa(10){// 函数体内初始化_year = year;_month = month;_day = day;}private:// 声明int _year; int _month;int _day;A _aa;//没有默认构造
};int main()
{Date d(2023, 11, 14);return 0;
}

2 如果不想使用A的默认构造的值呢?-->初始化列表

class A
{
public:A(int a = 10)//默认构造:_a(a){cout << "A(int a = 0)" << endl;}
private:int _a;
};class Date
{
public:Date(int year, int month, int day):_aa(1000){// 函数体内初始化_year = year;_month = month;_day = day;}private:// 声明int _year; int _month;int _day;A _aa;//调用默认构造
};int main()
{Date d(2023, 11, 14);return 0;
}

尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量, 一定会先使用初始化列表初始化

四 初始化列表中的初始化顺序

成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后 次序无关

class A
{
public:A(int a):_a1(a), _a2(_a1){}void Print() {cout << _a1 << " " << _a2 << endl;}
private:int _a2;int _a1;
};int main() {A aa(1);aa.Print();
}

先走的_a2, 此时_a1还没有初始化, 给的随机值,.

五 总结

初始化列表解决的问题:

1、必须在定义的地方显示初始化 引用 const 没有默认构造自定义成员

2、有些自定义成员想要显示初始化,自己控制

尽量使用初始化列表初始化

构造函数能不能只要初始化列表,不要函数体初始化?

不能,因为有些初始化或者检查的工作,初始化列表也不能全部搞定

80-100%初始化列表搞定,还有需要用函数体,他们可以混着用

我们来看看下面这段代码

class Stack
{
public:Stack(int n = 2):_a((int*)malloc(sizeof(int)* n)), _top(0), _capacity(n){//...//cout << "Stack(int n = 2)" << endl;if (_a == nullptr){perror("malloc fail");exit(-1);}memset(_a, 0, sizeof(int) * n);}//...int* _a;int _top;int _capacity;
};class MyQueue
{
public:MyQueue(int n1 = 10, int n2 = 20)//形成默认构造函数:_s1(n1), _s2(n2){}private:Stack _s1;Stack _s2;int _size = 0;
};int main()
{MyQueue q1;MyQueue q2(100, 100);//有初始化列表那就先走初始化列表return 0;
}

这样我们就能控制我们怎样控制我们的默认构造.

这节是对上一节类和对象(2)构造函数的续集, 建议两个章节要有先后理解, 本节内容比较简单, 注重理解 上一节的博客【C++】类和对象(2)--构造函数-CSDN博客

析构函数 【C++】类和对象(4)--析构函数-CSDN博客

继续加油!  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/191301.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

链表题(4)

本章内容 正文开始前给大家推荐个网站&#xff0c;前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。 今天继续给大家带来链表的相关练习题。 相交链表 这道题来自力扣网&#xff0c;链接…

9 STM32标准库函数 之 独立看门狗(IWDG)所有函数的介绍及使用

9 STM32标准库函数 之 独立看门狗&#xff08;IWDG&#xff09;所有函数的介绍及使用 1. 图片有格式该文档修改记录&#xff1a;总结 函数描述格式&#xff1a; 函数名外设函数的名称函数原形原形声明功能描述简要解释函数是如何执行的输入参数{x}输入参数描述输出参数{x}输出…

AIGC创作系统ChatGPT源码,AI绘画源码,支持最新GPT-4-Turbo模型,支持DALL-E3文生图

一、AI创作系统 SparkAi创作系统是基于OpenAI很火的ChatGPT进行开发的Ai智能问答系统和Midjourney绘画系统&#xff0c;支持OpenAI-GPT全模型国内AI全模型。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如…

原型网络Prototypical Network的python代码逐行解释,新手小白也可学会!!-----系列6 (承接系列5)

文章目录 一、原始代码---随机采样和评估模型二、详细解释分析每一行代码 一、原始代码—随机采样和评估模型 def randomSample(self,D_set): #从D_set随机取支持集和查询集&#xff08;20个类中的其中一个类&#xff0c;shape为[20,105,105]&#xff09;index_list list(ran…

任你五花八门预训练方法,我自监督学习依然能打!

长时间没看论文&#xff0c;外面已经发展成这样了&#xff1f; 以下都是新paper&#xff0c;挑了几个感兴趣的&#xff0c;一起粗略看看吧~ Battle of the Backbones: A Large-Scale Comparison of Pretrained Models across Computer Vision Tasks GitHub | https://github.…

【APUE】补充 — 基于管道的线程池

目录 一、引言 二、代码实现 三、思考 一、引言 在线程章节的 3.2 部分&#xff0c;我们曾经提到过线程池的实现 在当时的代码中&#xff0c;我们仅仅用的一个 int 类型的变量来表示这个“池”&#xff0c;用来存放任务 显然这个池太小了&#xff0c;如果下游线程很多&am…

肖sir__linux讲解vim命令(3.1)

vim 命令 一、 vi/vim 编辑器共分为三种模式&#xff1a; 格式 &#xff1a;vim 文件名 命令模式&#xff08;Command mode&#xff09;&#xff0c;“ESC”或ctrlc键 输入模式&#xff08;Insert mode&#xff09; 底线命令模式&#xff08;Last line mode&#xff09; …

GamingTcUI.dll丢失修复,最全面的GamingTcUI.dll修复指南

热衷于电脑游戏的用户可能会在启动游戏时遇到这样的错误信息&#xff1a;"无法启动应用&#xff0c;因为找不到GamingTcUI.dll"。那么这个GamingTcUI.dll文件是什么&#xff1f;如何解决这个问题呢&#xff1f;我们将在本文中进行详细讲解。 一.GamingTcUI.dll是什么…

十个一手app拉新地推拉新推广接单平台,放单/接任务渠道

做过地推拉新的朋友一定都非常清楚&#xff0c;app拉新推广一手接单平台&#xff0c;和非一手接任务平台之间的收益差&#xff0c;可以用天壤之别来形容。那么一手app拉新渠道应该怎么找&#xff1f;下面这十个常见的地推拉新app接单平台&#xff0c;一定要收藏。 1. 聚量推客…

Gem5模拟器学习之旅

安装gem5 模拟器 翻译自官网&#xff08;https://www.gem5.org/documentation/learning_gem5/part1/building/&#xff09; 支持的操作系统和环境 gem5的设计考虑到了Linux环境。我们定期在 Ubuntu 18.04、Ubuntu 20.04 和 Ubuntu 22.04 上进行测试&#xff0c;以确保 gem5 在…

一文带你了解QT Model/View框架的设计思想和实现机制

目录 1、QT Model/View框架简介 1.1、QT Model/View是什么&#xff1f; 1.2、QT Model/View框架核心思想 1.3、Model/View框架工作机制 1.4、Model/View框架的类 2、Model 2.1模型简介 2.2、模型索引 2.3、数据角色 2.4、QStringListModel 2.5、QFileSystemModel 2…

Nginx反向代理和负载均衡

1.反向代理 反向代理&#xff08;Reverse Proxy&#xff09;方式是指以代理服务器来接受internet上的连接请求&#xff0c;然后将请求转发给内部网络上的服务器&#xff0c;并将从服务器上得到的结果返回给internet上请求连接的客户端&#xff0c;此时代理服务器对外就表现为一…