【C++】类和对象(三)

前言

📚作者简介:爱编程的小马,是一名大厂后端c++程序员。

📚本文收录于C++系列,本专栏主要是分享我所了解的c++知识,带领大家慢慢从了解c++到认识c++,持续更新!

📚相关专栏Linux正在发展,敬请期待!

📚本文主要内容:认识类和对象六个默认成员函数

目录

1.类的6个默认成员函数

2.拷贝构造函数

2.1 定义

2.2 特征

3.赋值运算符重载

3.1 定义

3.2 特性

 4.取地址重载函数

4.1  定义

4.2 特性

总结


1.类的6个默认成员函数

如果一个类中什么成员都没有,简称为空类。空类中真的什么都没有吗?并不是,任何类在什么都不写时,编译器会自动生成以下6个默认成员 函数。默认成员函数:用户没有显式实现,编译器会生成的成员函数称为默认成员函数。

分为构造函数,析构函数,拷贝构造函数,赋值重载函数,取地址重载函数(两个,一个是普通对象,一个是const对象),今天介绍后面四个。 

2.拷贝构造函数

2.1 定义

拷贝构造函数:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存 在的类类型对象创建新对象时由编译器自动调用。 

2.2 特征

拷贝构造函数也是特殊的成员函数,其特征如下: 

1、拷贝构造函数是构造函数的一个重载函数

2、拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错, 因为会引发无穷递归调用。

我先就这两点给大家举个例子

class Date
{
public:
	//构造函数
	Date(int year =1 , int month =1, int day=1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	//拷贝构造函数
	Date(Date& d)
	{
		_year = d._year;
		_month =d._month;
		_day = d._day;
	}

	void Print()
	{
		cout << _year << "/" << _month << "/" << _day << endl;
	}
private:
	//内置类型
	int _year;
	int _month;
	int _day;
};

int main()
{
	//构造函数什么时候会调用,类实例化一个新的对象就是之前没有的
	Date d1(2024, 8, 2);
	//什么时候会调用拷贝构造,第一就是函数传参,第二就是用已经存在的对象
	//去实例化一个新的对象
	Date d2 (d1);
	d1.Print();
	d2.Print();
	return 0;
}

 

 3、如果拷贝构造函数没有显式定义,编译器就会生成一个默认的拷贝构造函数,默认的拷贝构造函数是浅拷贝。

 

大家看,我把拷贝构造函数屏蔽了,还是可以用d1去初始化d2,那拷贝构造没有什么存在的意义呀,那编译器自己就能把拷贝构造写出来并且可以使用,其实不是这样的,编译器生成的默认拷贝构造函数已经可以完成字节序的值拷贝了,还需要自己显式实现吗? 当然像日期类这样的类是没必要的。那么下面的栈类呢?验证一下试试? 

 

 代码崩了,我调试给大家找找原因,这块难度比较大,我讲解详细一些。

同一块空间,释放两次,是不是就崩了?这就是C++为了补C语言浅拷贝(值拷贝)的一个坑,C++用了一个拷贝构造函数来解决问题,就是你函数传参之前,先去调用拷贝构造函数完成深拷贝,再调用函数完成功能。这块的深拷贝怎么写? 

Stack(Stack& s)
	{
		STDataType* tmp = (STDataType*)malloc(sizeof(STDataType) * s._size);
		_a = tmp;
		memcpy(_a, s._a, sizeof(STDataType) * s._size);
		_size = s._size;
		_capacity = s._capacity;
	}

思路:重新开辟一个新的空间,将原空间的内容拷贝过来,即可。

5. 拷贝构造函数典型调用场景:

使用已存在对象创建新对象

函数参数类型为类类型对象

函数返回值类型为类类型对象 

3.赋值运算符重载

3.1 定义

C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其 返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。

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

函数原型:返回值类型 operator操作符(参数列表) 

3.2 特性

1. 赋值运算符重载格式

参数类型:const T&,传递引用可以提高传参效率

返回值类型:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值 检测是否自己给自己赋值 

//拷贝构造函数
	Date(Date& d)
	{
		_year = d._year;
		_month =d._month;
		_day = d._day;
	}
	//赋值重载函数
	Date& operator = (const Date & d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
		return *this;
	}

2. 赋值运算符只能重载成类的成员函数不能重载成全局函数 

是因为定义为全局函数,编译器会产生调用歧义。 

大家可能觉得,有了拷贝构造,这俩功能不是一样吗?为什么要需要复制重载呢?其实是下面这个原因: 

3、用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝。注 意:内置类型成员变量是直接赋值的,而自定义类型成员变量需要调用对应类的赋值运算符 重载完成赋值。 

 4.取地址重载函数

4.1  定义

返回类的地址 

4.2 特性

1、一个是普通对象,一个是const对象

2、这两个默认成员函数一般不用重新定义 ,编译器默认会生成。 

3、这两个运算符一般不需要重载,使用编译器生成的默认取地址的重载即可,只有特殊情况,才需 要重载,比如想让别人获取到指定的内容! 

 日期类简单代码:

class Date
{
public:
	//构造函数
	Date(int year =1 , int month =1, int day=1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	//拷贝构造函数
	Date(Date& d)
	{
		_year = d._year;
		_month =d._month;
		_day = d._day;
	}
	//赋值重载函数
	Date& operator = (const Date & d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
		return *this;
	}
	//取地址重载函数
	Date* operator& ()
	{
		return nullptr;
	}

	const Date* operator& ()const
	{
		return this;
	}
	void Print()
	{
		cout << _year << "/" << _month << "/" << _day << endl;
	}
private:
	//内置类型
	int _year;
	int _month;
	int _day;
};

int main()
{
	const Date d1(2024, 8, 2);
	Date d3(2023, 7, 4);
	Date d4(2010, 7, 4);
	cout << d1.operator& () << endl;;
	cout<<&d3<<endl;
	cout << &d4 << endl;
	return 0;
}

总结

今天介绍了拷贝构造函数,赋值重载函数,取地址重载函数(两个,一个是普通对象,一个是const对象),明天给大家更新完整的日期类,学到这个地方就算入门了。

 如果这份博客对大家有帮助,希望各位给小马一个大大的点赞鼓励一下,如果喜欢,请收藏一下,谢谢大家!!!
制作不易,如果大家有什么疑问或给小马的意见,欢迎评论区留言

  • 13
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值