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

继续加油!  

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Word软件手动安装Zotero插件

文章目录 Word软件手动安装Zotero插件方法一方法二 参考资料 Word软件手动安装Zotero插件 方法一 关闭word在zotero中依次点击编辑—首选项—引用—文字编辑软件—重新安装加载项Microsoft word 方法二 寻找Zotero.dotm存储位置&#xff0c; 例如D:\Program Files\Zotero\ext…

Qt DragDrop拖动与放置

本文章从属于 Qt实验室-CSDN博客系列 拖放操作包括两个动作&#xff1a;拖动(drag)和放下(drop或称为放置)。 拖动允许 对于要拖出的窗口或控件&#xff0c;要setDragEnabled(true) 对于要拖入的窗口或控件&#xff0c;要setAcceptDrops(true) 下面以一个具体的用例进行说…

Accelerate 0.24.0文档 二:DeepSpeed集成

文章目录 一、 DeepSpeed简介二、DeepSpeed集成&#xff08;Accelerate 0.24.0&#xff09;2.1 DeepSpeed安装2.2 Accelerate DeepSpeed Plugin2.2.1 ZeRO Stage-22.2.2 ZeRO Stage-3 with CPU Offload2.2.3 accelerate launch参数 2.3 DeepSpeed Config File2.3.1 ZeRO Stage-…

什么是 IT 资产管理(ITAM),以及它如何简化业务

IT 资产管理对任何企业来说都是一项艰巨的任务&#xff0c;但使用适当的工具可以简化这项任务&#xff0c;例如&#xff0c;IT 资产管理软件可以为简化软件和硬件的管理提供巨大的优势。 什么是 IT 资产管理 IT 资产管理&#xff08;ITAM&#xff09;是一组业务实践&#xff…

【3dMax室内照明】如何在V-ray中设置照明分析?

如何在V-ray中设置照明分析&#xff1f; 在3dMax的V-Ray Next中添加了新的“照明分析”工具&#xff0c;以帮助您测量和分析场景中的灯光级别。您将能够创建假彩色热图和数据覆盖&#xff0c;以显示亮度&#xff08;以坎德拉为单位&#xff09;或照度&#xff08;以勒克斯为单位…

每天一点python——day67

#每天一点Python——67 #字符串判断方法&#xff1a;如图&#xff1a; #①判断指定字符串是否为合法标识符 shello,computer print(s.isidentifier()) #输出为False&#xff0c;不是合法标识符&#xff0c;这是因为标识符是由字母&#xff0c;数字&#xff0c;下划线组成&#…

安卓调用手机邮箱应用发送邮件

先来看看实现效果&#xff1a; 也不过多介绍了&#xff0c;直接上代码&#xff1a; private void openMail() {Uri uri Uri.parse("mailto:" "");List<ApplicationInfo> applicationInfoList getPackageManager().getInstalledApplications(Packa…

DPU国产生态版图又双叒扩大了

DPU朋友圈迎来30新伙伴&#xff01;近期&#xff0c;中科驭数已与联想、中科可控、统信、欧拉、龙蜥社区、新支点、亚信科技、人大金仓、瀚高、南大通用、GreatSQL、阿里云、曙光云等超30家关键厂商完成兼容性互认证。测试报告显示&#xff0c;中科驭数DPU系列产品在产品兼容性…

好消息!2023年汉字小达人市级比赛在线模拟题大更新:4个组卷+11个专项,助力孩子更便捷、有效、有趣地备赛

自从《中文自修》杂志社昨天发通知&#xff0c;官宣了2023年第十届汉字小达人市级比赛的日期和安排后&#xff0c;各路学霸们闻风而动&#xff0c;在自己本就繁忙的日程中又加了一项&#xff1a;备赛汉字小达人市级比赛&#xff0c;11月30日&#xff0c;16点-18点。 根据这几年…

ChatGPT只算L1阶段,谷歌提出AGI完整路线图

按照谷歌这个标准来看&#xff0c;大多数已有AI产品其实都分别进入了不同的AGI阶段&#xff0c;但只仅限于在技能水平上——要谈及通用性&#xff0c;目前只有ChatGPT等模型完全合格。 AGI应该如何发展、最终呈什么样子&#xff1f; 现在&#xff0c;业内第一个标准率先发布&a…

春秋云境靶场CVE-2022-32991漏洞复现(sql手工注入)

文章目录 前言一、CVE-2022-32991靶场简述二、找注入点三、CVE-2022-32991漏洞复现1、判断注入点2、爆显位个数3、爆显位位置4 、爆数据库名5、爆数据库表名7、爆数据库数据 总结 前言 此文章只用于学习和反思巩固sql注入知识&#xff0c;禁止用于做非法攻击。注意靶场是可以练…

任意注册漏洞

目录 一漏洞介绍 二实战演示 三漏洞修复 本文由掌控安全学院 - 小博 投稿 一漏洞介绍 1.未验证邮箱/手机号 情景&#xff1a;应用为了方便用户记录用户名&#xff0c;使用邮箱和手机号作为用户名&#xff08;因此很多应用在注册的时候就要求用户填写&#xff0c;多数时候…

java spring cloud 企业电子招标采购系统源码:营造全面规范安全的电子招投标环境,促进招投标市场健康可持续发展

功能描述 1、门户管理&#xff1a;所有用户可在门户页面查看所有的公告信息及相关的通知信息。主要板块包含&#xff1a;招标公告、非招标公告、系统通知、政策法规。 2、立项管理&#xff1a;企业用户可对需要采购的项目进行立项申请&#xff0c;并提交审批&#xff0c;查看所…

vscode远程连接服务器报错

报错&#xff1a; Bad owner or permissions on C:\\Users\\Alice/.ssh/config> 过程试图写入的管道不存在。 1.ping一下config里面ip 2.ping的通&#xff0c;不是网络问题 3.扩展 -> remote-ssh -> 设置 -> 扩展设置&#xff08;红框&#xff09; 4.输入config绝…

后端接口性能优化分析-2

常见思路 1.批量思想&#xff1a; 这个其实是一个最容易想到的代码层次的修改&#xff0c;其实对业务上来说&#xff0c;结果都是一样的&#xff0c;只不过这个涉及到了一件事就是&#xff0c;像数据库中发请求&#xff0c;是发十次还是发一次的问题。其原因最根本的还是&…

评论:AlexNet和CaffeNet有何区别?

一、说明 在这个故事中&#xff0c;我们回顾了AlexNet和CaffeNet。AlexNet 是2012 年ILSVRC&#xff08;ImageNet 大规模视觉识别竞赛&#xff09;的获胜者&#xff0c;这是一项图像分类竞赛。而CaffeNet是AlexNet的单GPU版&#xff0c;因此&#xff0c;我们平时在普通电脑的Al…

一文懂得电源模块过温保护测试方法 ate测试软件助力测试

过温保护测试是电源模块保护功能测试项目之一&#xff0c;也是电源模块测试的重要测试指标&#xff0c;以保证电源模块过温保护功能正常&#xff0c;确保电源模块不受损坏。用ate测试软件测试电源模块过温保护&#xff0c;不仅可以保证测试结果的准确性&#xff0c;还可以多维度…

revit获取FamilySymbol的name

因为想解析把Element的CategoryId跟FamilySymbolId解析并存下来&#xff0c;这样就可以还原Revit中项目浏览器&#xff0c;里面的族的结构层次了。 参考&#xff1a;Revit中“Category、Family、 Familysymbol、 FamilyInstance”之间的关系​​​​​​ 但是对于wall和floor等…

通过key在数仓里查询dt的时候报错

现象 Query failed (#20231114_080638_00103_iaf4c) in hive: line 3:11: Column tyc_web_company_workright cannot be resolved 原因 key应该被单引号括起来&#xff0c;字段名称才应该被双引号括起来 修改 把单引号换成双引号就好了

软件测试自学指南,十年阿里测试工程师的建议

通过技能提升&#xff0c;入行IT可以的&#xff0c;但得先积累足够的经验&#xff0c;才能拿高薪&#xff0c;有个成长的过程。 软件测试岗介绍 软件测试岗位主要负责系统的测试工作&#xff0c;属于IT项目中的质量管理&#xff08;QA&#xff09;模块。 这个岗位分为两种类…