类与对象(二)

在空类中,不是什么都没有的,会默认生成六个成员函数;

本篇文章记录的是前四个默认成员:

目录

1. 构造函数

概念 

特征

几类构造函数

a. 自动生成的默认构造函数

 b. 无参构造函数(默认构造函数)

c. 带参的构造函数 

d. 全缺省构造函数(也是默认构造函数的一种)

重载

总结

2. 析构函数 

概念

特征

析构顺序

3. 构造拷贝函数

概念

特征

传值传参递归问题

4.运算符重载

概念

类外

类中

 调用方式更改:

优化


以日期类为例:

class Date
{
public:
	void DateInit(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. 构造函数

概念 

顾名思义,函数的创建,也就是函数的初始化

构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,保证每个数据成员都有 一个合适的初始值,并且在对象的生命周期内只调用一次。

特征

1. 函数名与类名相同。
2. 无返回值。
3. 对象实例化时编译器自动调用对应的构造函数。
4. 构造函数可以重载。

日期类中,我们用的是DateInit函数对类进行初始化,其实,没有此函数的话,类会生成默认的构造函数,进行初始化。

几类构造函数

a. 自动生成的默认构造函数

当对象没有显示构造函数时:

生成默认构造函数

class Date
{
public:

	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1;
	return 0;
}

 b. 无参构造函数(默认构造函数)

	//2.无参数构造函数
	Date()
	{}

	//2.无参数构造函数
	Date()
	{
		_year = 2022;
		_month = 5;
		_day = 15;
	}

c. 带参的构造函数 

	//3.带参的构造函数
	Date(int year,int month,int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}

正确创建如下: 

一般使用带参的构造函数时,将参数都写为缺省参数,更方便使用。 

d. 全缺省构造函数(也是默认构造函数的一种)

	//3.带参的构造函数
	Date(int year=2000,int month=1,int day=1)
	{
		_year = year;
		_month = month;
		_day = day;
	}

重载

 

随机值原因:

编译器生成的默认构造函数对于内置类型的成员不做处理

对于自定义类型的成员才会做处理

创建自定义类型

  

总结

如果一个类中的成员全部都是自定义类型,那么可以使用默认生成的函数

如果有内置类型成员或者需要显示传参初始化,那么都需要自己实现构造函数

不传参就可以调用的就是默认构造函数

2. 析构函数 

概念

与构造函数功能相反,析构函数不是完成对象的销毁,局部对象销毁工作是由编译器完成的。而对象在销毁时会自动调用析构函数,完成类的一些资源清理工作。

特征

1. 析构函数名是在类名前加上字符 ~。
2. 无参数无返回值。

	~Date()
	{

	}
	~Date()
	{
		_year = 1;
		_month = 1;
		_day = 1;
	}

3. 一个类有且只有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。

也遵循对内置类型不处理,对自定义类型调用他自己的析构函数处理的原则。


4. 对象生命周期结束时,C++编译系统系统自动调用析构函数。


5.编译器生成的默认析构函数,会对自定类型成员调用它的析构函数。

 

严格来说,日期类是不需要写析构函数的,内置类型随着程序结束时,内置类型成员也随之销毁。但是手动开辟的空间需要些析构函数进行数据处理,要不然会造成内存泄露的问题这就是对内置类型不处理的劣势。因此对于手动开辟空间的内置类型要写出析构函数。

如栈:

析构顺序

相同类创建的对象,析构顺序与构建顺序相反

创建两个栈的对象

 析构的顺序与构造的顺序相反,ST2后构造,那么他就先析构

3. 构造拷贝函数

概念

只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存在的类类型对象创建新对象时由编译器自动调用。
就是用一个已存在的对象取创建另一个一摸一样的对象,相当于复制粘贴

特征

1. 拷贝构造函数是构造函数的一个重载形式。
2. 拷贝构造函数的参数只有一个且必须使用引用传参,使用传值方式会引发无穷递归调用。

如下:

传值传参递归问题

同类型的对象传值传参要调用拷贝构造

如果不加引用的话:无限递归

尽量前面加上const,因为参数不需要改变

	//拷贝构造函数
	Date(const Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}

3. 若未显示定义,系统生成默认的拷贝构造函数。

默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝我们叫做浅拷贝,或者值拷贝。

4.有动态开辟空间的对象不能进行如下拷贝构造

浅拷贝:

	//拷贝构造->浅拷贝
	Stack(const Stack& ST)
	{
		_a = ST._a;
		_top = ST._top;
		_capacity = ST._capacity;
	}

当程序结束时,析构函数开始进行数据清理:

先对ST2进行清理:

再对ST1进行清理:

这样类型的对象进行构造拷贝,不能使用浅拷贝,要使用深拷贝才行,在之后的笔记中会详细讲到。

4.运算符重载

概念

运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。

为了让自定义类型可以使用各种运算符,可以进行运算符重载

比如想要比较两个日期是否相同:

不可以直接进行比较,那么我们可以使用运算符重载

函数名字为:关键字operator后面接需要重载的运算符符号。

类外

//参数:看运算符来定:两个相比较,那么就有两个形参
//返回值:看运算后的结构,比较相等返回真假即可,即bool
bool operator==(Date d1, Date d2)
{
	return d1._year == d2._year&&
		d1._month == d2._month&&
		d1._day == d2._day;
}

 这种方式不推荐

类中

原因是,这里存在三个形参,还有一个隐含的this指针,因此要去掉一个参数 ,且调用时也要改变,如下:

编译器会处理为:d1.operator==(&d1,d2) 

 调用方式更改:

优化

对上面传参的部分可以进行优化,传值调用会进行拷贝构造,这里应该传引用,并且对参数不更改,应加const

	bool operator==(const Date& d2)
	{
		return _year == d2._year&&
			_month == d2._month&&
			_day == d2._day;
	}

不能被重载的符号

域作用符 ::

sizeof

三目运算符?:          . 操作符       .*操作符

注意事项

重载运算符必须有一个类类型参数,不能对内置类型进行重载

用于内置类型的运算符,不能改变其含义,比如重载+时,内容不能创建成 -

作为类成员的重载函数,形参比操作数目看起来少一个参数,因为有一个默认的形参this


这里对运算符重载做了一个简单的介绍,简单应用,下一篇文章将以日期类对运算符重载进行详解,这里有什么不对的地方欢迎各位评论指正,一起进步!

评论 32
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

今年依旧去年春

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值