C++基础知识点(六)类和对象

目录

一、构造函数初始化列表

二、类型转换


往期文章👇

C++基础知识点(五)

C++基础知识点(四)

C++基础知识点(三)

C++基础知识点(二)

C++基础知识点(一)

一、构造函数初始化列表

构造函数初始化还有⼀种⽅式,就是++初始化列表++

初始化列表的使⽤⽅式是:

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

代码示例:

cpp 复制代码
class Date
{
public:
	Date(int year, int month, int day)
		:_year(year)
		, _month(month)
		, _day(day)
	{}
private:
	int _year;
	int _month;
	int _day;
};

😜 每个成员变量在初始化列表中只能出现⼀次,语法理解上初始化列表可以认为是每个成员变量定义初始化的地⽅。

🫣 但是也存在特例:

1️⃣ 引⽤成员变量

2️⃣ const成员变量

3️⃣ 没有默认构造的类类型变量

这些变量必须放在初始化列表位置进⾏初始化,否则会编译报错。

代码示例:

cpp 复制代码
class Time
{
public:
	Time(int hour)
		:_hour(hour)
	{
		cout << "Time()" << endl;
	}
private:
	int _hour;
};

class Date 
{
public:
	Date(int& x, int year, int month, int day)
		:_year(year)
		,_month(month)
		,_day(day)
		,_t(12)
		,_n(1)
		,rx(x)
	{}
	// error C2512: "Time": 没有合适的默认构造函数可⽤
	// error C2530 : "Date::_ref" : 必须初始化引⽤
	// error C2789 : "Date::_n" : 必须初始化常量限定类型的对象
private:
	int _year;
	int _month;
	int _day;
	const int _n;
	int& rx;
	Time _t;
};

🙃 C++11⽀持在成员变量声明的位置给缺省值,这个缺省值主要是给没有显⽰在初始化列表初始化的成员使⽤的。

举个例子,首先是有在初始化列表初始化的成员:

cpp 复制代码
class Date
{
public:
	Date(int year, int month, int day)
		:_year(year)
		,_month(month)
		,_day(day)
	{}
	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}

private:
	int _year = 1;
	int _month = 1;
	int _day = 1;

};
int main()
{

	Date d1(2025, 10, 13);
	d1.Print();

	return 0;
}

可以发现正常输出d1传入的日期:2025-10-13

如果没有在初始化列表初始化的成员,C++11⽀持在成员变量声明的位置给缺省值:

cpp 复制代码
class Date
{
public:
	Date(int year, int month, int day)
		:_year(year)
	{}
	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}

private:
	int _year = 1;
	int _month = 1;
	int _day = 1;

};
int main()
{

	Date d1(2025, 10, 13);
	d1.Print();

	return 0;
}

我们可以看到这时候 _month 和**_day** 的缺省值都定为1,因此当我们运行程序的时候发现输出的结果为:2025-1-1

因此我们可以总结一下初始化列表的知识点:

  1. 尽量使⽤初始化列表初始化,因为那些你不在初始化列表初始化的成员也会⾛初始化列表,如果这个成员在声明位置给了缺省值,初始化列表会⽤这个缺省值初始化。

😉如果你没有给缺省值,对于没有显⽰在初始化列表初始化的内置类型成员是否初始化取决于编译器,C++并没有规定。

😍对于没有显⽰在初始化列表初始化的⾃定义类型成员会调⽤这个成员类型的默认构造函数,如果没有默认构造会编译错误。

😘⽆论是否显⽰写初始化列表,每个构造函数都有初始化列表。

🥲⽆论是否在初始化列表显⽰初始化,每个成员变量都要⾛初始化列表初始化。

  1. 初始化列表中按照成员变量在类中声明顺序进⾏初始化,跟成员在初始化列表出现的的先后顺序⽆关,建议声明顺序和初始化列表顺序保持⼀致。

用一个题目进行解释👇:

😇下⾯程序的运⾏结果是什么?
A. 输出 1 1
B. 输出 2 2
C. 输出 1 随机值

cpp 复制代码
class A
{
	public :
	A(int a)
		: _a1(a)
		, _a2(_a1)
	{}
	void Print() 
	{
		cout << _a1 << " " << _a2 << endl;
	}
private:
	int _a2 = 2;
	int _a1 = 2;
};
int main()
{
	A aa(1);
	aa.Print();
}

程序运行结果如下👇:

🤩从运行结果可以看出,初始化列表中是按照成员变量在类中声明顺序进⾏初始化,而跟成员在初始化列表出现的的先后顺序⽆关。

二、类型转换

(1) C++⽀持内置类型隐式类型转换为类类型对象,需要有相关内置类型为参数的构造函数。

(2) 构造函数前⾯加explicit就不再⽀持隐式类型转换。

(3) 类类型的对象之间也可以隐式转换,需要相应的构造函数⽀持。

cpp 复制代码
class A
{
	public:
	// 构造函数explicit就不再⽀持隐式类型转换
	// explicit A(int a1)
	A(int a1)
		:_a1(a1)
	{}
	//explicit A(int a1, int a2)
	A(int a1, int a2)
		:_a1(a1)
		,_a2(a2)
	{}
	void Print()
	{
		cout << _a1 << " " << _a2 << endl;
	}
	int Get() const
	{
		return _a1 + _a2;
	}
private:
	int _a1 = 1;
	int _a2 = 2;
};
class B
{
	public:
	B(const A& a)
		: _b(a.Get())
	{}
private:
	int _b = 0;
};
int main()
{
	// 1构造⼀个A的临时对象,再⽤这个临时对象拷⻉构造aa3
	// 编译器遇到连续构造+拷⻉构造->优化为直接构造
	A aa1 = 1;
	aa1.Print();
	const A& aa2 = 1;
	// C++11之后才⽀持多参数转化
	A aa3 = { 2,2 };
	// aa3隐式类型转换为b对象
	// 原理跟上⾯类似
	B b = aa3;
	const B& rb = aa3;
	return 0;
}

💯如果这篇文章对你有用的话,请继续关注!

相关推荐
小此方2 小时前
Re:从零开始学C++(二)基础精讲·下篇:内联函数与空指针
开发语言·c++
心.c2 小时前
初步了解Next.js
开发语言·前端·javascript·js
桃花岛主702 小时前
go-micro,v5启动微服务的正确方法
开发语言·后端·golang
Kiri霧2 小时前
Go 结构体高级用法
开发语言·后端·golang
csdn_life182 小时前
Rustrover 如何像Java一样直接 进行调试和运行
java·开发语言·rust
草莓熊Lotso3 小时前
C++11 核心特性实战:列表初始化 + 右值引用与移动语义(附完整代码)
java·服务器·开发语言·汇编·c++·人工智能·经验分享
初夏睡觉4 小时前
从0开始c++,但是重置版,第1篇(c++基本框架)
开发语言·c++
草莓熊Lotso4 小时前
GCC/G++ 编译器完全指南:从编译流程到进阶用法(附实操案例)
linux·运维·服务器·网络·c++·人工智能·自动化
workflower9 小时前
时序数据获取事件
开发语言·人工智能·python·深度学习·机器学习·结对编程