21天学会C++:Day12----初始化列表

news2024/11/22 13:34:24

· CSDN的uu们,大家好。这里是C++入门的第十一讲。
· 座右铭:前路坎坷,披荆斩棘,扶摇直上。
· 博客主页: @姬如祎
· 收录专栏:C++专题

 

目录

1. 初始化列表

1.1 引入

1.2 初始化列表

1.3 初始化列表的注意事项 

1.4 初始化列表成员变量的初始化顺序 

2. 同一表达式连续构造的优化

3. 静态成员变量与静态成员函数

4. 内部类


1. 初始化列表

1.1 引入

还记得我们之前在学习类和对象的时候是怎么给类的成员变量 "初始化" 的吗?我们是通过构造函数在函数体内部给成员变量赋值的。为什么说是赋值而不是说初始化呢?因为成员变量的初始化就不是在函数体内部完成的!而是一个叫初始化列表的东西中完成的!

我们定义了一个类A,在构造函数中我们对成员变量进行了多次赋值!以此来证明构造函数的函数体不是对成员变量进行初始化的地方。

class A
{
public:
	A(int x = 0, int y = 0)
	{
		_x = x;
		_x = 5;
		_y = y;
	}
private:
	int _x;
	int _y;
};


int main()
{
	A a(2, 3);
	return 0;
}

1.2 初始化列表

我们先来看看初始化列表的语法吧:

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

比如下面的代码:

class A
{
public:
	A(int x = 0, int y = 0)
		:_x(x)
		,_y(y + x)
	{}
private:
	int _x;
	int _y;
};

在括号里面也是可以写表达式的哦! 

我们的C++祖师爷为什么要设计出初始化列表呢?那肯定是因为函数体内的赋值无法对所有类型的成员变量进行赋值。我们来看下面的代码:

我们看到类的成员变量如果有const 修饰的变量或者引用,在构造函数的函数体内部赋值就会直接报错了!根据报错提示,我们也能够隐隐猜到构造函数的函数体不是成员变量初始化的地方!

对于const修饰的变量 和引用都有一个共同的特性:在定义的时候必须初始化!我们又知道了初始化列表才是成员变量真正定义的地方!所以const 修饰的变量和引用就必须在初始化列表中初始化:这样的代码就没有什么问题啦!

class A
{
public:
	A(int x = 0, int y = 0)
		:_x(x)
		,_y(y)
	{}
private:
	const int _x;
	int& _y;
};

1.3 初始化列表的注意事项 

我们来看看初始化列表的注意事项:

1:每个成员变量在初始化列表中最多出现一次

2:类中包含以下成员,必须放在初始化列表位置进行初始化: 引用成员变量 const成员变量 自定义类型成员,且该类没有默认构造函数时

我们来看第一点:每个成员变量在初始化列表中最多出现一次。我们现在知道了初始化列表是成员变量定义的地方。如果一个成员变量在初始化列表中出现两次,那么这个变量不就是被定义了两次嘛!这当然是不被允许的!

 

第二点: 引用变量 与 const 修饰的成员变量为什么只能在初始化列表中初始化你应该已经明白了!那么没有默认构造函数的自定义类型为什么也必须要在初始化列表中初始化呢?

你还记得默认构造函数的定义嘛:默认构造函数就是不用传参就可以直接调用的构造函数。

来看下面的代码:我们定义了类A,自己写了带参的构造函数,那么编译器则不会为类A提供默认构造函数。我们又定义了类B,成员变量是自定义类型。我们尝试在B的构造函数中给成员变量赋值。

class A
{
public:
	A(int x, int y)
		:_x(x)
		,_y(y)
	{}
private:
	int _x;
	int _y;
};

class B
{
public:
	B(A a)
	{
		_a = a;
	}

private:
	A _a;
};

我们编译器直接报错了:类 A 不存在默认构造函数!为什么会报这个错误呢?我们知道初始化列表是成员变量定义的地方,那么类B的成员变量会在初始化列表中有类似这样的定义:A _a。即在定义的过程中他会去调用A的默认构造函数,但是因为 A 没有默认构造函数自然就会报错了!

 

也就是说:对于自定义类型的成员变量,如果该成员变量没有显示在初始化列表中初始化, 就会调用该自定义类型的默认构造函数

那如果我们在初始化列表中显示初始化,就会调用对应的构造函数对自定义类型的成员变量进行初始化。

1.4 初始化列表成员变量的初始化顺序 

先不着急讲解知识点,我们来看看下面的代码的输出结果是什么?

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();
	return 0;
}

A:输出 1 1

B:程序崩溃

C:编译不通过

D:输出 1 随机值

答案是D哦!初始化列表的初始化顺序并不是按照初始化列表中的书写顺序来的!而是按照成员变量的声明顺序来的!_a2先声明,那么就会先初始化_a2,因此_a2用还未初始化的_a1初始化就是随机值。所以说为了避免出现这样的错误,初始化列表的书写顺序最好与成员变量的声明顺序一致

 

最后一点:还记得我们在类中给成员变量缺省值的操作嘛!那个缺省值其实就是给初始化列表初始化的! 

2. 同一表达式连续构造的优化

大家觉得下面的代码有没有问题呢?

class A
{
public:
	A(int x)
		:_x(x)
	{}

	A(const A& a)
	{
		_x = a._x;
	}

private:
	int _x;
};


int main()
{
	A a = 2;
	return 0;
}

 你变异之后发现变异通过并且运行良好!这是为啥呢?整形可以直接赋值给自定义类型?其实不是的啦!这其中发生了隐式类型转化,C++98的语法:单参数的构造函数支持隐士类型转换。所以说 A a = 2;其实是用 2 这个整形调用了A的构造函数,构造了一个A的对象,然后在通过拷贝构造来构造 a 这个对象!

如果你不能理解我们可以拿一个内置类型来举例:

我们有一个整形变量直接将他赋值给一个double变量,看看编译器是怎么做的。

这个道理和 A a = 2;是一样的撒!所以在这一个表达式中调用了构造函数和拷贝构造函数!于是编译器看不下去了!他将这个表达式优化成了直接调用构造函数来构造 a 这个对象。编译器是容忍不了一个表达式出现两个构造函数的调用的!

那你可能不相信我的解释,你说:有没有可能并没有一个临时对象被构造出来,而本来就是用 2 直接构造a这个对象。那我们来看看这个代码:A& a = 2; 报错:非常量引用的初始值必须为左值,也就是说,在给 a 赋值的时候,a引用的是一个右值,自然就报错了。

可是我们如果用的是const的引用呢?发现就没有报错了!我们知道临时对象具有常性,加上const才能对其进行引用。但是这也并不能说明通过2构造了一个A的对象哇!你可能会说a就是引用的2这个右值嘛!

 

OK,那很巧,C++中有一个关键字能够废除这种隐式类型转换:explicit。如果真如你所有说 a 能够引用 2 这个右值,那么废除 这种隐式类型转换也不会报错吧!

很遗憾他报错了!那么说明这种隐式类型转换是真实存在的!

3. 静态成员变量与静态成员函数

假设我们现在有这样一个需求,需要你统计出一个类实例化出了多少个对象!你激动的说到,这个我会呀!对象实例化不是都要调用构造函数吗,对象销毁不是都要调用析构函数嘛,那么我只要维护一个全局变量count,然后再构造函数里对count++,析构函数里面对count--,不就大功告成了吗?是的你很厉害,也很聪明!

int _count;

class A
{
public:
	A(int x = 0)
		:_x(x)
	{
		_count++;
	}

	A(const A& a)
	{
		_x = a._x;
		_count++;
	}

	~A()
	{
		_count--;
	}

private:
	int _x;
};

可是有一天,来了一个程序员,看到了这个count,这是干什么用的?一下就给你把count给改了!显然不行!

原因还是在与全局变量无法得到有效的封转保护!于是我们的静态成员变量他来了!静态成员变量可以理解为全局变量的封转,使得变量更好被维护。静态成员变量应该怎么初始化呢?很简单:

class A
{
public:
	A(int x = 0)
		:_x(x)
	{
		_count++;
	}

	A(const A& a)
	{
		_x = a._x;
		_count++;
	}

	~A()
	{
		_count--;
	}

private:
	int _x;
	static int _count;
};

静态成员变量属于一个类,不单独属于任何一个对象!静态成员变量是所有对象共享的。访问静态变量的时候只要突破类域和访问权限就可以直接访问。可以通过类域,也可以通过对象访问。

但是吧静态成员变量设置为共有又有一点不太好!因此我们需要提供一个函数来访问静态成员变量。

 我们提供了一个普通的成员函数,发现必须需要有对象才能访问这个函数!但是我们的需求是随时访问这个函数,因此我们将这个函数变为静态函数!静态函数没有this指针,不能访问非静态的成员变量(因为函数访问普通的成员变量就是通过this指针访问的嘛)。通过对象或者类名都可以直接访问。前提是有权限哦!

4. 内部类

内部类 概念:如果一个类定义在另一个类的内部,这个内部类就叫做内部类。

内部类是一个独立的类,它不属于外部类,更不能通过外部类的对象去访问内部类的成员。外部类对内部类没有任何优越的访问权限。

注意:内部类就是外部类的友元类,参见友元类的定义,内部类可以通过外部类的对象参数来访问外部类中的所有成员。但是外部类不是内部类的友元。

特性:

1. 内部类可以定义在外部类的public、protected、private都是可以的。

2. 注意内部类可以直接访问外部类中的static成员,不需要外部类的对象/类名。

3. sizeof(外部类) = 外部类,和内部类没有任何关系。

内部类C++用的不多,Java喜欢用内部类。内部类供大家了解一下吧! 

 

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

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

相关文章

字符集(ASCII、GBK、Unicode、UTF-8)

1、字符集基础知识 计算机底层不可以直接存储字符的。计算机中底层只能存储二进制&#xff08;0、1&#xff09;二进制是可以转换成十进制的结论&#xff1a;计算机底层可以表示十进制编号。计算机可以给人类字符进行编号存储&#xff0c;这套编号规则就是字符集。 2、ASCII字符…

如何像微信一样扫码自由?

https://github.com/devilsen/CZXing 我在使用zxing的总是想扫码的时候怎么才能够快速校准&#xff0c;多个二维码扫描的时候怎么才能指定二维码呢。于是我在Github上找到了CZxing这个控件。在使用的时候发现了有些小问题。 扫码结果没有回调。 回调没有反应&#xff1b;是因…

二维码智慧门牌管理系统:提升城市管理效率与服务水平

文章目录 前言一、系统原理及特点二、系统的优势与应用 前言 在当今快速发展的信息化时代&#xff0c;如何有效地管理城市地址信息成为了各大城市面临的重要问题。传统的门牌管理系统已经无法满足现代城市的需求&#xff0c;而二维码智慧门牌管理系统作为全新的解决方案&#…

数据库开发-MySQL

数据库设计-DDL 下面我们就正式的进入到SQL语句的学习&#xff0c;在学习之前先给大家介绍一下我们要开发一个项目&#xff0c;整个开发流程是什么样的&#xff0c;以及在流程当中哪些环节会涉及到数据库。 项目开发流程 需求文档&#xff1a; 在我们开发一个项目或者项目当中…

Linux文件内容显示练习

1.新建2个文件b1.txt b2.txt ,使用vim打开b1.txt 输入“Hello World”字符串,将b1.txt硬链接到b2.txt 查看2个文件的硬连接数 [rootserver ~]# vim b1.txt [rootserver ~]# ln b1.txt b2.txt #建立硬链接 [rootserver ~]# stat b2.txt [rootserver ~]# stat b1.txt [r…

现货黄金的价格如何变动

现货黄金每天的交易时间很长&#xff0c;价格几乎全天24小时都处于波动之中&#xff0c;由于受到各种政治、经济因素的影响&#xff0c;价格波动有时可以来得十分迅猛&#xff0c;在一小时就可以波动二、三十美元&#xff0c;但有时却可以连续几天都维持在数美元的区间内波动。…

《使用 sCrypt 构建井字游戏》课程上线

《使用 sCrypt 构建井字游戏》课程上线 Learn sCrypt。Learn sCrypt 是一个交互式学习网站&#xff0c;旨在帮助开发者更快、更轻松地学习和掌握比特币智能合约开发语言 sCrypt。 井字游戏非常简单&#xff0c;就是使用两个玩家(分别是 Alice 和 Bob)的比特币地址初始化合约&a…

Spring框架——介绍与基本概念!

一、Spring框架概述 1.什么是Spring Spring是一个轻量级的Java 开发开源框架&#xff0c;用于构建企业级应用程序。它提供了一组广泛使用的技术和API&#xff0c;包括依赖注入、AOP、数据访问、事务管理、Web开发和集成测试等。它是为了解决企业应用开发的复杂性而创建的。框…

c盘中temp可以删除吗?appdata\local\temp可以删除吗?

http://www.win10d.com/jiaocheng/22594.html C盘AppData文件夹是一个系统文件夹&#xff0c;里面存储着临时文件&#xff0c;各种应用的自定义设置&#xff0c;快速启动文件等。近期有用户发现appdata\local\temp占用了大量的空间&#xff0c;那么该文件可以删除吗&#xff1f…

Java 21 发布,带来诸多新特性又一次创新的飞跃

一、引言 2023年9月19日&#xff0c;Oracle公司正式发布了JDK 21&#xff0c;这是按照六个月发布周期准时交付的第12个功能版本。 这种可预测性让开发者能够轻松地管理他们对创新的采用&#xff0c;感谢稳定的改进流。JDK 21不仅包含了数千个性能、稳定性和安全性更新&#xf…

比特币上的可验证延迟函数

可验证延迟函数 (VDF) 是一种需要大量 顺序计算 来评估但可以快速验证的函数。我们首次在比特币上实现了它。VDF 作为密码学技术可用于构建大量新应用程序&#xff0c;例如公共随机信标、计算时间戳和数据复制证明。 VDF 场景 链上随机信标 在区块链中很难实现随机性&#xf…

php生成二维码合成文字、背景图并保存本地图片

目录 1、实现效果&#xff0c;二维码二维码合成文字、背景图 2、下载并引入qrcode 3、创建static文件夹下载字体和背景图到这 4、创建test2.php&#xff0c;合成代码 1、实现效果&#xff0c;二维码二维码合成文字、背景图 2、下载并引入qrcode 1、到phpqrcpde官网下载类库…

UltraEdit 22 编辑器 for Mac

UltraEdit 是一款功能强大的文本编辑器和源代码编辑器。它具有多种功能&#xff0c;适用于程序员、网站开发人员和其他需要处理大量文本内容的用户。 UltraEdit 提供了正则表达式搜索和替换功能&#xff0c;可以快速查找和修改文本中的特定内容。它还支持多文件编辑和多窗口布局…

掌握文案新技能,拓世AI让你成为朋友圈文案达人

“人生如戏&#xff0c;戏如人生”&#xff0c;这是一句缥缈却真实的话&#xff0c;我们在生活中扮演着各种角色&#xff0c;经营自己的人生。如同美国社会学家戈夫曼提出的“拟剧论”&#xff1a;他将社会和人生比作一个大舞台&#xff0c;我们都在关心如何在众多观众面前打造…

Linux动态库

定义&#xff1a;动态函数库&#xff0c;是在程序执行时动态&#xff08;临时&#xff09;由目标程序去调用 优点&#xff1a; 调用时不复制&#xff0c;程序运行时动态加载到内存&#xff0c;供程序调用&#xff0c;系统只加载一次&#xff0c;多个程序可以共用&#xff0c;…

百亿、补贴这种低价怎么控

随着电商平台流量竞争的激烈演变&#xff0c;越来越多的促销形式进入人们的眼球&#xff0c;而店铺最简单的营销就是通过价格&#xff0c;所以低价销售成了各平台吸引消费者的方式&#xff0c;百亿补贴因为其独特的属性&#xff0c;与平台挂钩&#xff0c;通过“全网最低价”的…

VB在窗体中显示1000以内的完数

VB在窗体中显示1000以内的完数 在窗体中显示1000以内的完数&#xff08;如果一个整数的所有因子&#xff08;包括1&#xff0c;但不包括本身&#xff09;之和与该数相等&#xff0c;则称这个数字为完数。例如6123&#xff0c;所以6是一个完数&#xff09; Private Function Is…

【前端知识】Three 学习日志(五)—— 点光源辅助观察

Three 学习日志&#xff08;五&#xff09;—— 点光源辅助观察 一、引入点光源辅助观察 // 光源辅助观察 const pointLightHelper new THREE.PointLightHelper(pointLight, 10); scene.add(pointLightHelper);二、改变点光源位置 // 点光源位置 pointLight.position.set(2…

[补题记录] Atcoder Beginner Contest 308(C~E)

URL&#xff1a;https://atcoder.jp/contests/abc308 目录 C Problem/题意 Thought/思路 Code/代码 D Problem/题意 Thought/思路 Code/代码 E Problem/题意 Thought/思路 Code/代码 C Problem/题意 给出n个&#xff08;a&#xff0c;b&#xff09;数对&#xff…

短视频矩阵系统源代码开发搭建分享--代码开源SaaS

一、什么是短视频矩阵系统&#xff1f; 短视频矩阵系统是专门为企业号商家、普通号商家提供帐号运营从流量 到转化成交的一站式服务方案&#xff0c;具体包含&#xff1a;点赞关注评论主动私信 &#xff0c;评论区回复&#xff0c;自动潜客户挖掘&#xff0c;矩阵号营销&#x…