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

news2024/11/27 11:42:23

目录

一 引入

二 初始化列表概念

三 初始化列表特性

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;//引用 -->error
                  const 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博客

继续加油!  

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

TSINGSEE青犀视频平台EasyCVR自定义可视化页面一览

视频监控TSINGSEE青犀视频平台EasyCVR能在复杂的网络环境中&#xff0c;将分散的各类视频资源进行统一汇聚、整合、集中管理&#xff0c;在视频监控播放上&#xff0c;视频安防监控汇聚平台可支持1、4、9、16个画面窗口播放&#xff0c;可同时播放多路视频流&#xff0c;也能支…

数据结构—队列的实现

前言&#xff1a;上次我们已经学习了数据结构中一个重要的线性表—栈&#xff0c;那么我们这一次就来学习另外一个重要的线性表—队列。 目录&#xff1a; 一、 队列的概念 二、 队列的实现&#xff1a; 1.队列的创建 三、 队列的操作 1.初始化队列 2.队尾入队列 3.队头出队列…

KOSMOS-G-图像文本结合控制生成

文章目录 摘要引言算法多模态语言建模图像解码器对齐微调instruction 实验结论 论文&#xff1a; 《Kosmos-G: Generating Images in Context with Multimodal Large Language Models》 github&#xff1a; https://github.com/microsoft/unilm/tree/master/kosmos-g 摘要 当…

朋友过生日送什么葡萄酒好呢

现在葡萄酒不但是活跃气氛、制造仪式感的酒精饮品&#xff0c;也是朋友之间礼尚往来的最佳礼品。有人问&#xff0c;朋友过生日送什么葡萄酒好呢&#xff1f;云仓酒庄的品牌雷盛红酒LEESON分享人们觉得红葡萄似乎太严肃&#xff0c;白葡萄酒颜色又太清淡&#xff0c;送一款什么…

pip安装到哪里

可以这样证明&#xff1a;

《QT从基础到进阶·二十六》绘制多个图形项(QGraphicsRectItem,QGraphicsLineItem,QGraphicsPolygonItem)

这个demo用QT实现了对多个图形项的绘制&#xff0c;包括矩形的绘制&#xff0c;直线的绘制和多边形的绘制&#xff0c;是之前一章中绘制矩形的增强版&#xff0c;之前一章节关于矩形的绘制可以参考&#xff1a;《QT从基础到进阶十五》用鼠标绘制矩形&#xff08;QGraphicsView、…

远程登录Linux方法(Linux平台相互远程;Windows远程登录Linux、远程编码、文件传输;无法远程登录的问题解决;c程序的编译)

在实际使用Linux系统过程中我们不可避免的需要远程登录Linux&#xff0c;这是因为未来大家使用Linux服务器的时候你所对应的那台Linux服务器不一定提供界面(服务器可能在外地)。本篇将会介绍远程登录Linux的方法。 文章目录 1. SSH介绍2. Linux平台相互远程及文件传输2.1 Linux…

准备搞OpenStack了,先装一台最新的Ubuntu 23.10

正文共&#xff1a;1113 字 25 图&#xff0c;预估阅读时间&#xff1a;2 分钟 依稀记得前面发了一篇Ubuntu的安装文档&#xff08;66%的经验丰富开发者和69%的学生更喜欢的Ubuntu的安装初体验&#xff09;&#xff0c;当时安装的是20.04.3的版本&#xff0c;现在看来已经是非常…

C语言数据结构-----栈和队列(概念,代码实现及简单练习)

前言 本篇主要介绍栈和队列的相关知识&#xff0c;练习以及代码实现。 代码主要展示部分功能的实现。完整代码在gitee上查看。 链接: 栈和队列的完整代码实现 文章目录 前言1.栈1.1 栈的概念及结构1.2 栈的实现1.3 栈的代码实现1.3.1 栈的初始化1.3.2 栈顶插入1.3.3 栈顶删除1…

若依框架修改包名报错

1.首先看下报错截图 启动GateWay 2.这个是因为 我改了里面的包名就是下面 ruoyi改成screen爆了上面的问题 3.那么关键的来了&#xff0c;我测了下 改了core不管启动gateway还是modules里面任何一个都会爆打不开工具类的问题 &#xff0c;我看了其他pom也没有引用core&#xff…

功能强大的国产API管理神器 Eolink,亲测好用

前言 大家好&#xff0c;我是小月&#xff0c;今天给大家讲讲最近很火的Eolink&#xff0c;一款功能强大且非常实用的国产 API管理工具。在我们日常的前端、后端开发测试过程中经常会用到API&#xff0c;特别是在大型项目中API管理工具也就必不可少。工欲善其事必先利其器&…

[模版总结] - 树的基本算法1 - 遍历

树结构定义 一种非线性存储结构&#xff0c;具有存储“一对多”关系的数据元素集合 种类 General Tree TrieB/B 树二叉树 满/完满/完全二叉树 完美BT : 除了叶子结点外所有节点都有两个字节点&#xff0c;每一层都完满填充完全BT&#xff1a; 除最后一层以外其他每一层都完美…

FaceBook登录提示密码错误的原因及解决方法

下面这一种类型的提示密码错误&#xff0c;大家首先能够想到的可能就是本身的账号密码有错误&#xff0c;但这个只代表其一。有一种情况的话&#xff0c;他可能根本不是账号或者密码的错误&#xff0c;他仅仅是因为注册的地方和登录的地方不太一样&#xff0c;也会造成这样的结…

【JavaEE初阶】IP协议简介

文章目录 前言&#x1f334;IP协议的概念&#x1f333;IP数据报&#x1f6a9;IPv4协议头格式&#x1f6a9;IPv6的诞生 &#x1f38d;IP地址&#x1f6a9;IP地址的格式&#xff1a;&#x1f6a9;IP地址的分类&#x1f388;网络号与主机号的划分 &#x1f6a9;特殊的IP地址&#…

QGIS之十九矢量投影

效果 步骤 1、准备数据 2、Qgis矢量投影 Qgis工具箱中搜索“投影” 3、结果

算法笔记-第七章-栈的应用(未完成)

算法笔记-第七章-栈的应用 栈的基本常识栈的解释一栈的解释二 栈的操作序列合法的出栈序列可能的出栈序列补充知识点 后缀表达式&#xff08;无优先级&#xff09; 栈的基本常识 栈&#xff08;Stack&#xff09;是只允许在一端进行插入或删除操作的线性表。 栈的解释一 栈的…

Vue dev-tools的安装

安装 Vue 开发者工具&#xff0c;装插件调试Vue应用 1.通过谷歌应用商店来进行安装&#xff08;国外网站&#xff09; 2.极简插件&#xff1a; 搜索 Vue -> 下载解压 -> 浏览器扩展模式打开&#xff0c;开发者模式 -> 将解压的CRX文件拖拽安装 -> 插件详情 &…

YOLOV8目标识别——详细记录从环境配置、自定义数据、模型训练到模型推理部署

一、概述 Yolov8建立在Yolo系列历史版本的基础上&#xff0c;并引入了新的功能和改进点&#xff0c;以进一步提升性能和灵活性。Yolov8具有以下特点&#xff1a; 高效性&#xff1a;Yolov8采用了新的骨干网络、新的Ancher-Free检测头和新的损失函数&#xff0c;可在CPU到GPU的…

在SpringBoot中使用EhCache缓存

在使用EhCache缓存之前&#xff0c;我们需要了解的是EhCache缓存是啥&#xff1f; Ehcache的概述 Ehcache是一个开源的Java缓存框架&#xff0c;用于提供高效的内存缓存解决方案&#xff0c;他可以用于缓存各种类型的数据&#xff0c;包括对象&#xff0c;查询结果&#xff0…

软件测试行业趋势分析

1 绪论 本文先对互联网对时代和社会变革进行了论述&#xff0c;然后再由互联网时代对软件工业模式变革进行了介绍&#xff0c;最后引出附属于软件工业的测试行业在新形势下的需求变化&#xff0c;并对趋势进行了分析&#xff0c;并最终给出了相关的从业人员的职业发展建议。 …