C++初始化列表详解 + explicit关键字

news/2024/9/21 18:48:39 标签: c++, 开发语言

构造函数初始化列表

构造函数:

class Date
{
public:
	// 构造函数
	Date(int year = 0, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
        //可以修改值
        _year = 2024;
        _month = 9;
        _day = 21;
	}
private:
	int _year;
	int _month;
	int _day;
};

这样的构造函数和普通函数一样,都是在函数体里对成员变量的值进行修改。 

但是初始化并不是在函数体里实行的。而是在函数体还没执行之前就已经初始化了。当然这个初始化是我们可以控制的

引入初始化列表:

初始化列表就是在函数体之前,以 冒号开头,逗号分割的对成员函数进行初始化。如下代码。 

class Date
{
public:
	// 构造函数
	Date(int year = 0, int month = 1, int day = 1)
		:_year(year)
		, _month(month)
		, _day(day)
	{}
private:
	int _year;
	int _month;
	int _day;
};

 attention

1.初始化列表不管你写于不写,都是会执行的。(因为变量都是初始化后才能赋值)

int i = 1;//正确
i = 1;//错误

2.每个成员变量在初始化列表中只能出现一次。(重复初始化是错的)

int i = 1;//初始化1次
int i = 2;//重复初始化错误

3.成员变量的 初始化和初始化列表的顺序无关,而是和声明的顺序有关。

#include<iostream>
using namespace std;
const int i = 0;
class Date
{
public:
	// 构造函数
	Date(int year = 0, int month = 1, int day = 1)
		: _day(i++)
		, _year(i++)
		,_month(i++)
	{}
private:
	int _year; // == 0 
	int _month; // == 1
	int _day; // == 2
    //i == 3
};

如上,初始化顺序依然是year month day。 结果year == 0,month == 1,day == 1.

我们是根据声明的顺序去找对应的初始化方案。

初始化列表的作用:

1. 提高运行效率:

要初始化的成员变量无非两种:内置类型和自定义类型

对于内置类型而言:使用初始化列表和不使用相差不大。

// 使用初始化列表
int a = 10;
// 在构造函数体内初始化(不使用初始化列表)
int a;
a = 10;

 对于自定义类型而言:使用初始化列表可以提升效率。

class Time
{
public:
	Time(int hour = 0)
	{
		_hour = hour;
	}
private:
	int _hour;
};
class Test
{
public:
	// 在构造函数体内初始化(不使用初始化列表)
	Test(int hour) 

	{ //初始化列表调用一次Time类的构造函数(不使用初始化列表但也会走这个过程)
		Time t(hour);// 调用一次Time类的构造函数
		_t = t;// 调用一次Time类的赋值运算符重载函数
	}
private:
	Time _t;
};

上述代码,我们没有用初始化列表初始化_t 对象 

导致的问题就是我们在创建对象时,已经默认初始化了一次,现在_t 是存在的,但是值是不清楚的。所以要对其进行更改,就得先创建一个对象,然后通过赋值重载给_t 对象

如果使用初始化列表:初始化列表在对象创建时,通过传入参数的值直接对成员变量初始化。就省去了赋值的操作

Test(int hour) 
    :_t(hour)
	{}

2. 对于必须要初始化的成员变量,必须放在初始化列表

1.const成员变量:

很好理解,因为const int i ;const int 这类变量是必须初始化的。因为const 关键字是定义了一个常量,常量是初始化后不允许被修改的。如果不初始化,那就违背了const的初衷

2.引用类型的成员变量:

一样的,引用类型的变量必须被初始化。(因为引用就是起外号,没有说先起一个外号留着备用的,而是根据一个人取的。)

const和引用类型都是语法要求的

3.没有默认构造函数的类:

默认构造函数:并不只是单一的指我们没写时,系统自动添上的。事实上有三种默认构造函数

1.没有构造函数时系统自动添上(只要有构造函数,这个就失效了)

2.构造函数的参数是全缺省的(参数都有缺省值)

Date(int year = 0, int month = 1, int day = 1)
		:_year(year)
		, _month(month)
		, _day(day)
	{}

3. 没有参数的构造函数。

三小只必须用初始化列表初始化 ,因为语法要求。

explicit关键字

explicit(显示)关键字只用于单参数的构造函数。相反的就是implicit(隐式)

首先介绍一下什么是隐式类型转换

int a = 20;
double sum = 0;
sum = a;//隐式类型转换
//double tmp = a,sum = tmp;
sum = a + 20.0;//隐式类型转换

sum = a时,会有一个转换的过程。编译器会临时使用内部的数据结构或寄存器来存储转换后的值,但是这个值不可见。然后再把这个值赋给sum。这就是隐式类型转换。a + 20.0也是同理。

对于单参数的构造函数而言默认情况下是不使用explicit关键字的,也就是说是可以进行隐式类型转换的

未加入explicit关键字

class Date
{
public:
	// 构造函数
	Date(int year = 0)
		: _year(1)
	{}
private:
	int _year; 
};

int main()
{
    Date year1(1);//对
    Date year2 = 2;//对
    Date year3 = 'a';//对
    Date year4 = 4.0;//对
}

对于上述代码我们只有一个参数 下面的year1是正常调用构造函数。

year2的实际做法是:转换过程中有一个Date对象用2初始化,然后把这个对象赋值给了year2. 

Date year2 = 2;
//拆分过程(抽象)
Date tmp(2);
year2 = tmp;

year3 和 year4 的做法都是:先将'a'转换为int(ASCII码表),4.0转为int。然后进行year2的做法。两次隐式类型转换

加入了explicit关键字

1.有效的添加

	explicit Date(int year = 0)
		: _year(1)
	{}

现在隐式类型转换失效,上述的year2 year3 year4全失效。

 2.无效的添加

	explicit Date(int year,int month)
		: _year(year),
          _month(month)
	{}

当有两个以上的参数时,explicit等于没有,因为无法赋值两个变量

int i = 1,3;

没有这种初始化方法。

3.例外添加

explicit Date(int year,int month=1,int day=1)
		: _year(year),
          _month(month),
          _day(day)
	{}

当只有第一个参数没有缺省值而其他参数都有缺省值时,这时候也可以进行隐式类型转换。所以explicit生效。


http://www.niftyadmin.cn/n/5669278.html

相关文章

神经网络 归一化层

为什么要进行网络归一化层&#xff1f; 神经网络训练过程中&#xff0c;当网络层数较多的时候&#xff0c;每一轮训练每个网络层的参数都会发生变化&#xff0c;那么网络层参数变化会有什么影响呢&#xff1f; 1. 向网络中输入相同分布的样本时&#xff0c;由于每一层网络的参…

PCF8563驱动源码

提供年、月、日、星期&#xff0c;时、分、秒计时&#xff0c;使用外置32.768Khz晶振。低后备电流&#xff1a;0.25uA&#xff0c;VDD3.0V&#xff0c;温度25℃。IIC接口&#xff0c;速度最高400KHz。可编程时钟输出&#xff0c;可以供其他设备使用&#xff0c;可输出的时钟频率…

Java 19 新特性-结构化并发(Structured Concurrency)[Preview]

Java 19 新特性&#xff1a;结构化并发&#xff08;Structured Concurrency&#xff09;[预览] Java 19 在并发编程领域引入了一个全新的概念——结构化并发&#xff08;Structured Concurrency&#xff09;&#xff0c;作为预览功能发布。这一特性旨在简化并发任务的管理&…

[Python数据可视化]探讨数据可视化的实际应用:三个案例分析

数据可视化是理解复杂数据集的重要工具&#xff0c;通过图形化的方法&#xff0c;可以直观地展示信息、趋势和模式。本文将深入探讨三个实际案例&#xff0c;包括健康数据分析、销售趋势分析、城市交通流量分析。每个案例将提供假设数据、详细注释的代码及分析结果。 案例 1: …

mdadm 命令:软RAID管理

一、命令简介 ​mdadm​ 是 Linux 下用于管理软件 RAID 设备的工具&#xff0c;可以创建、管理和监控软件 RAID 阵列。 ‍ 创建 RAID 需要多个环节&#xff0c;多个命令搭配使用&#xff1a; ​gdisk​ ​命令创建格式为 Linux RAID​ ​的磁盘分区​mdadm​ ​命令将多个 …

web 动画库

web动画库 动画领域有一个比较知名的CSS库&#xff1a;Animate.css&#xff0c;它提供了60多种动画&#xff0c;满足一般网页的需求&#xff0c;比如淡入淡出、闪现等等一系列日常动画&#xff0c;不过虽然它能满足日常需求&#xff0c;但是一些复杂的场景就需要靠JS手动去操作…

oracle 11g写一个判断是否是身份证的函数,函数名称为:FUN_IS_IDENNO

下面是一个用于判断是否是身份证号码的Oracle 11g函数&#xff08;FUN_IS_IDENNO&#xff09;。身份证号码通常为18位&#xff08;或者旧的15位&#xff09;&#xff0c;前17位为数字&#xff0c;第18位为数字或字母X&#xff0c;并且需要符合一定的规则&#xff0c;例如出生日…

开源网安多城联动、多形式开展网安周公益活动,传播网络安全知识

9月9日至15日&#xff0c;以“网络安全为人民&#xff0c;网络安全靠人民”为主题的2024年国家网络安全宣传周将在全国范围内统一开展&#xff0c;通过多样的形式、丰富的内容&#xff0c;助力全社会网络安全意识和防护技能提升。开源网安今年继续为各地企业、群众带来了丰富的…