首页 > 编程语言 >C++ 类和对象(初始化列表)

C++ 类和对象(初始化列表)

时间:2024-11-27 13:32:49浏览次数:9  
标签:初始化 变量 int 成员 C++ 列表 构造函数

目录

一、前言

二、正文

1.初始化列表

1.1初始化的格式

1.2初始化列表的使用

1.2.1引用成员变量初始化

1.2.2const成员变量

1.2.3没有默认构造函数的成员变量必须在初始化列表初始化

2.成员变量声明处给缺省值

一、前言

前面我们已经用所学知识运算符重载写了一个日期计算器:https://blog.csdn.net/yiqingaa/article/details/143954136?

现在让我们开启C++知识新篇章——初始化列表吧

二、正文

1.初始化列表

  • 之前我们实现构造函数时,初始化成员变量主要使用函数体内赋值,构造函数初始化还有一种方式,就是初始化列表,初始化列表的使用方式是以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个“成员变量“后面跟一个放在括号中的初始值或表达式。
  • 每个成员变量在初始化列表中只能出现一次,语法理解上初始化列表可以认为是每个成员变量定义初始化的地方。
  • 引用成员变量,const成员变量,没有默认构造的类类型变量,必须放在初始化列表位置进行初始化,否则会编译报错。
  • C++11支持在成员变量声明的位置给缺省值,这个缺省值主要是给没有显示在初始化列表初始化的成员使用的。
  • 尽量使用初始化列表初始化,因为那些你不在初始化列表初始化的成员也会走初始化列表,如果这个成员在声明位置给了缺省值,初始化列表会用这个缺省值初始化。如果你没有给缺省值,对于没有显示在初始化列表初始化的内置类型成员是否初始化取决于编译器,C++并没有规定。对于没有显示在初始化列表初始化的自定义类型成员会调用这个成员类型的默认构造函数,如果没有默认构造会编译错误。
  • 初始化列表中按照成员变量在类中声明顺序进行初始化,跟成员在初始化列表出现的的先后顺序无关。建议声明顺序和初始化列表顺序保持一致。
  • 初始化列表总结:
  • 无论是否显示写初始化列表,每个构造函数都有初始化列表;
  • 无论是否在初始化列表显示初始化,每个成员变量都要走初始化列表初始化;

1.1初始化的格式

//这里我们假设定义一个Date类名
class Date
{
public:
	//这个是我们常规使用函数体内赋值的方法实现构造函数
	Date(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	//下面是我们用初始化列表实现构造函数
	Date()
		:_year(1)
		,_month(1)
		,_day(1)
	{}
private:
	int _year;
	int _month;
	int _day;
};

我们仔细观察不难得出初始化列表的格式是:

类名()
:成员变量1(表达式1)
,成员变量2(表达式2)
,成员变量3(表达式3)
,成员变量4(表达式4)
...
{}         //值得注意的是初始化列表是{}上面定义的而非{}内定义
          //其次就是编译器运行逻辑循序是先运行{}上面的,再访问
         //{}里面的。

1.2初始化列表的使用

//这里我们假设定义一个Date类名
class Date
{
public:
	//这个是我们常规使用函数体内赋值的方法实现构造函数
	Date(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	//下面是我们用初始化列表实现构造函数
	Date()
		:_year(1)
		,_month(1)
		,_day(1)
	{}
private:
	int _year;
	int _month;
	int _day;
};

上面这串代码中展现了函数体内赋值和初始化列表实现构造函数的区别。但是你可能有些疑惑:这也没什么不同啊,都一样能运行为什么还需要了解初始化列表呢,不是多此一举吗?

其实,但看这幅图上的代码段确实看不出什么区别,但是其实有些特殊成员变量必须要用初始化列表进行初始化。

例如:1、引用成员变量/2、const成员变量/3、没有默认构造函数的成员变量

上面这三个特殊成员变量都必须用初始化列表初始化。

  • 1.2.1引用成员变量初始化
#include<iostream>
using namespace std;
class Date
{
public:
	Date(int& x, int year = 1, int month = 1, int day = 1)
		:_year(year)
		,_month(month)
		,_day(day)
		,_ref(x)
	{
		cout << "Date()" << endl;
	}
private:
	int _year;
	int _month;
	int _day;

	int& _ref;//引用成员变量初始化
};
int main()
{
	int i = 0;
	Date d1(i);
	return 0;
}

上面这两幅图是我们为引用成员变量使用初始的结果,那么如果我们在初始化列表中显示写引用成员变量会发生什么呢?

这里我们可以看出,如果我们有引用类成员变量,我们没有在初始化列表中为该成员变量初始化的话,编译器会报错(该成员必须初始化之类的警告)。这不可避免,因为C++设定就是如此。

这时你可能又有疑惑了,我非要使用初始化列表的方式初始化引用成员变量(_ref)吗?我偏使用原来的方法初始化(之前我们是使用函数体内赋值实现初始化的)那让我们看看用原来的办法行不行呢:

很遗憾,很明显这是行不通的,大家不必纠结为什么不可以,只要记住就行。毕竟人家C++是这么规定的。

  • 1.2.2const成员变量

从这里可以看出,初始化列表中没有初始化const成员变量,下面报的错误和上面引用成员变量不在初始化列表中初始化是差不多的,因此const成员变量的使用规则都是和上面引用类成员都是大同小异的。大家可以和上面1.2.1引用变量进行类比。

  • 1.2.3没有默认构造函数的成员变量必须在初始化列表初始化
#include<iostream>
using namespace std;
class Time
{
public:
	Time(int hour)//这里我们没有给hour缺省值,意味着这里我们必须手动传参才能完成Time类对象的初始化
		:_hour(hour)//即这里不是默认构造参数,默认构造函数可以概括为不需要传实参就可以用的构造函数就是默认构造函数
	{
		cout << "Time()" << endl;
	}
private:
	int _hour;
};
class Date
{
public:
	Date(int year = 1, int month = 1, int day = 1)
		:_year(year)
		,_month(month)
		,_day(day)
		,_t(1)
	{
		cout << "Date()" << endl;
	}
private:
	int _year;
	int _month;
	int _day;

	Time _t; //自定义类型Time
};
int main()
{
	int i = 0;
	Date d1;
	return 0;
}

从这里看出当我们的没有默认构造函数的成员变量(_t)在初始化列表中初始化后程序正常运行了。那么如果_t没有在初始化列表中,完成初始化会出现什么情况呢?

我们在构造函数那一节讲过了自定义类型成员变量必须调用该成员变量的默认构造函数进行初始化,否则就会报错。(忘了的小伙伴可以回顾一下往期分享构造函数https://blog.csdn.net/yiqingaa/article/details/143490439?

因此,从这里我们知道自定义类型成员变量必须调用该成员变量的默认构造函数进行初始化,那么你既没有默认构造函数又不想在初始化列表中进行初始化。你不报错,谁报错?

那么这个问题该怎么解决了呢?

  1. 如果该自定义类型成员变量在没有默认构造函数的前提下,必须在初始化列表中完成初始化。
  2. 如果该自定义类型成员变量,一开始就有默认构造函数,那么是否在初始化列表中完成初始化,完全看大家的心情。其实既然已经有默认构造函数了,是否在初始化列表中初始化已经无所谓了。

这个时候可能有小伙伴们要问了,如果该自定义类型成员既写了默认构造函数,又在初始化列表中初始化了,编译器会怎么做呢?

其实如果我们在初始化列表中已经对该自定义类型成员完成初始化了,那么默认构造函数的缺省值也就没用了,这就类似于我们有一个默认构造函数Date(int year=1,int year=1,int day=1)。现在我们定义实例化对象Date d1(2024,11,25);因为我们已经传参了,这个时候缺省值也就没用了或者说我们传的实参优先级更高。

2.成员变量声明处给缺省值

 还记的上面我们写的初始化列表总结中:无论是否在初始化列表显示初始化,每个成员变量都要走初始化列表初始化;这句话吗?

其实在我们为成员变量初始化的时候,即使该成员变量没有出现在初始化列表中,这个成员变量依旧会走初始化列表。

在理解上面这句话之前,先让我们学习一个新的概念:给成员变量声明的地方给缺省值。

我们知道,当我们写出上面这些成员变量的时候,其实并不是定义(定义是需要开空间的)而只是声明,只有我们创建实例化成员,例如Date d1的时候这些成员才会有对应的空间(空间大小取决于各自成员变量的类型例如_year是int类型,那么它的_year的大小就是4个字节)d1的大小是所有成员变量按照结构体内存对齐原则决定的。

既然这只是声明,那我们给一个只是声明的成员给缺省值有什么意义呢?

其实这也是初始化列表的一部分。我们给声明的成员变量一个缺省值,当该成员变量没有显示在初始化列表中完成初始化的,编译器会按照所给缺省值为相应成员变量完成初始化(虽然我们的成员变量没有出现在初始化列表中,其实这个过程也是在初始化列表中完成的,即这个缺省值就是给初始化列表的缺省值)。

如图所示,即使我们const int类成员变量_n没有显示在初始化列表进行初始化,但是由于我们给他一个缺省值2,它依旧就完成了初始化,其实这个过程只是将缺省值代入到了初始化列表中(因为无论是否在初始化列表显示初始化,每个成员变量都要走初始化列表初始化;

哪怕它不显示在初始化中,实际上还是在初始化列表中完成初始化的。

3.全篇总结

哈哈,懒画图了,直接把课件给你们扣下来了。

三、结语

今天的初始化列表就分享到这了 ,帅哥美女们我们下次再见~

标签:初始化,变量,int,成员,C++,列表,构造函数
From: https://blog.csdn.net/yiqingaa/article/details/144020182

相关文章

  • 【leetcode】括号生成 c++回溯法
    22.括号生成 22.括号生成-力扣(LeetCode)数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。示例1:输入:n=3输出:["((()))","(()())","(())()","()(())","()()()"]示例2:输入:n=1输出:["()"]提示:1<=n<=8......
  • Day41--什么时候需要初始化对象
    Day41--什么时候需要初始化对象需要初始化对象的情况使用对象的成员变量或方法时当你需要访问对象的成员变量或者调用对象的方法时,必须先初始化对象。例如:classMyClass{intvalue;voidprintValue(){System.out.println("Valueis:"+value);......
  • C++ 多继承基类析构虚函数
    Demo:classAnimal{public:Animal(){cout<<"animal..."<<endl;}virtual~Animal(){cout<<"~animal..."<<endl;}virtualvoidShowAnimal()=0;};classCa......
  • 帝国CMS列表页调用图集幻灯片并自定义样式
    <?phpif(!empty($r[morepic])){$morepic=$r['morepic'];$mpr=explode(PHP_EOL,$morepic);$mpcount=count($mpr);for($mpi=0;$mpi<$mpcount;$mpi++){$mp=explode('::::::',$mpr[$mpi]);$sho......
  • 国家和地区代码列表,ISO 3166-1:2006
    本文根据ISO3166-1:2006(InternationalStandardNormeInternationale)英文版(含2007年补充说明)整理。与ISO3166-1:1997相比,2006版新增的国家和地区已在备注栏中标出。2006版与1997版相比删除的条目是:南斯拉夫YugoslaviaYU\YUG\891。本文所列的国家地区中文名称,依照GB/T......
  • c++ 程序来计算三角形的面积(Program to find area of a triangle)
    给定一个三角形的边,任务是求出该三角形的面积。例如: 输入:a=5,b=7,c=8输出:三角形面积为17.320508输入:a=3,b=4,c=5输出:三角形面积为6.000000方法:可以使用以下公式简单地计算三角形的面积。其中a、b和c是三角形边长, s=(a+b+c)/2 下面是上......
  • C++异常
    目录1.C语言传统的处理错误的方式2.C++异常概念3.异常的使用1.异常的抛出和捕获2.异常的重新抛出3.异常安全4.异常规范4.自定义异常体系5.C++标准库的异常体系6.异常的优缺点1.C语言传统的处理错误的方式        传统的错误处理机制:终止程序,如assert,缺......
  • 有什么方案可以提高无限滚动列表的性能?
    无限滚动列表的性能优化核心在于减少DOM操作和渲染的开销。以下是一些常见的优化方案:1.窗口化渲染(Windowing)这是最常用的也是最有效的优化方法。核心思想是只渲染当前视口可见的部分和一小部分缓冲区,而不是渲染整个列表。当用户滚动时,动态更新渲染的列表项,回收不再可见的......
  • 【最新原创毕设】基于Java的面向中职物联网专业教师的课程资源服务平台(免费领源码)可做
    目录摘要1绪论1.1选题背景与意义1.2国内外研究现状1.3论文结构与章节安排2系统分析2.1可行性分析2.2系统流程分析2.2.1系统开发流程2.2.2用户登录流程2.2.3系统操作流程2.2.4添加信息流程2.2.5修改信息流程2.2.6删除信息流程2.3 系统......
  • (分享源码)计算机毕业设计必看必学 上万套实战教程手把手教学JAVA、PHP,node.js,C++、pyth
    摘 要随着互联网大趋势的到来,社会的方方面面,各行各业都在考虑利用互联网作为媒介将自己的信息更及时有效地推广出去,而其中最好的方式就是建立网络管理系统,并对其进行信息管理。由于现在网络的发达,果园信息统计管理系统的信息通过网络进行信息管理掀起了热潮,所以针对果园信......