C++基础精讲篇第8讲:类中赋值运算符重载函数及const成员函数特性详解

C++基础精讲篇第6讲:类中构造函数和析构函数特性详解_King_lm_Guard的博客-CSDN博客https://blog.csdn.net/King_lm_Guard/article/details/126043552C++基础精讲篇第7讲:类中拷贝构造函数特性详解_King_lm_Guard的博客-CSDN博客https://blog.csdn.net/King_lm_Guard/article/details/126049876        本讲内容基于上一讲中分析的C++类中6个默认的成员函数,在前两讲中详细分析了构造函数、析构函数与拷贝构造函数,这一讲博主接着分析赋值运算符重载函数相关特性。

目录

1、运算符重载基本概念

2、赋值运算符重载

2.1 赋值运算符重载格式

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

2.3  用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝

3、前置++和后置++重载

 3.1 前置++详细分析

3.2 后置++详细分析

4、const成员函数

 5、取地址及const取地址操作符重载

6、运算符重载注意事项

7、结语


1、运算符重载基本概念

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

函数名字:关键字operator后面接需要重载的运算符符号。
函数原型返回值类型 operator操作符(参数列表)。

详解:参数列表分为(左操作数、右操作数)。返回类型是由操作符号决定的,比如:两个同类型的变量相减,返回的差值是整型则返回类型为int ,如果为字符型则返回char,如果返回值就是该类的类型,那就以该类名作为返回对象接收。

//判断日期类变量d1和d2是否相等,对运算符“==”进行重载
bool operator==(const Date& d1, const Date& d2)
{
	return d1._year == d2._year
		&& d1._month == d2._month
		&& d1._day == d2._day;
}

        运算符重载运用格式如上例所示,对符号“==”进行运算符重载,比较两个日期类是否相等。其中左操作数为d1,右操作数为d2,返回类型用bool接收。

2、赋值运算符重载

2.1 赋值运算符重载格式

1、参数类型:const T&,传递引用可以提高传参效率;
2、返回值类型:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值;
3、检测是否自己给自己赋值;
4、返回*this :要复合连续赋值的含义。

示例:

        以如下代码为例说明:

#define _CRT_SECURE_NO_WARNINGS 
#include<iostream>
using namespace std;
//运算符重载

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

private:
	int _year;
	int _month;
	int _day;
};

void Test()
{
	Date d1(2022, 7, 30);
	//书写方式1
	//Date d2(d1);
	//书写方式2
	Date d2;
	d2.operator=(d1);
	//书写方式3
	Date d3 = d2;
}

int main()
{
	Test();
	return 0;
}

程序执行结果:可以发现三种不同的写法同样可以实现对类变量d2的赋值运算符重载。


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

示例:将赋值运算符重载成全局函数时演示情况

注意:由于此时是全局函数,而在类Date中,原则上成员变量_year、_month、_day三者应该在类中设置为private,而不是public,但为了演示全局函数,所以将成员函数设置为public,此时可以在该类外直接访问成员变量,如下程序所示:

 此时程序运行结果显示编译出错,如上所示,这是因为:

        赋值运算符如果不显式实现,编译器会生成一个默认的。此时用户再在类外自己实现一个全局的赋值运算符重载,就和编译器在类中生成的默认赋值运算符重载冲突了,故赋值运算符重载只能是类的成员函数。


2.3  用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝

        注意:内置类型成员变量是直接赋值的,而自定义类型成员变量需要调用对应类的赋值运算符重载完成赋值。

示例:

class Time
{
public:
	//构造函数
	Time(int hour=1,int minute=1,int second=1)
	{
		_hour = hour;
		_minute = minute;
		_second = second;
	}
	//赋值运算符重载
	Time& operator=(const Time& t)
	{
		if (this != &t)
		{
			_hour = t._hour;
			_minute = t._minute;
			_second = t._second;
		}
		return *this;
	}
private:
	int _hour;
	int _minute;
	int _second;
};

class Date
{
public:
	//构造函数
	Date(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	//得到私有的自定义类型Time类的成员变量
	Time& Get_Time()
	{
		return this->_t;
	}

private:
	// 基本类型(内置类型)
	int _year ;
	int _month;
	int _day ;
	// 自定义类型
	Time _t;
};


int main()
{
	Date d1(2022, 7, 30);
	Time t(12, 24, 36);
	d1.Get_Time().operator=(t);
	Date d2;
	d2 = d1;
	return 0;
}

程序执行结果:

 补充:

        同拷贝构造函数一样,编译器生成的默认赋值运算符重载函数可以完成字节序的值拷贝,诸如像日期类这种类类型的对象,因为其内部的成员变量如:_year、_month、_day等都是内置类型,虽然成员变量_t是Time类类型的,但在拷贝的时候编译器会去调用自定义类型的赋值运算符重载函数,如程序中所示,所以可以实现拷贝。

        但对于栈、队列等需要额外开辟空间的类来说(如下所示),如果只是简单的采用值拷贝,在销毁空间的时候会存在对同一块空间多次释放的情况,为此,需要采用深拷贝相关知识进行解决该类问题,这在后面的学习中我会为大家带来讲解。

3、前置++和后置++重载

        因为前置++和后置++的运算符相同,为了在使用过程中加以区分,在C++中,使用函数重载进行区分,也就是说在后置++重载中增加一个int类型参数和前置++构成函数重载。但调用函数时该参数用户不用传递,编译器自动传递。


 3.1 前置++详细分析

        前置++是返回+1之后的结果,因为在类中this指针指向的对象函数结束后不会销毁,故以引用方式返回提高效率,这种返回方式在上一讲中讲解拷贝构造函数时进行过详细分析,如果不用引用,而是用传值返回,则会形成临时拷贝,相比传引用返回效率较低。(还是提供上一讲分析的传引用返回和传值返回的区别)。

前置++用法示例说明


3.2 后置++详细分析

        后置++是先使用后+1,因此需要返回+1之前的旧值,故需在实现时需要先将this保存一份,然后给this+1。因为在使用后置++时,需要保存旧值,所以需要创建临时变量temp保存旧值*this,然后再讲该临时变量返回,因此此时只能以传值的方式返回,不能传引用返回

后置++用法示例说明

4、const成员函数

        将const修饰的“成员函数”称之为const成员函数,const修饰类成员函数,实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改。

示例:下面的程序执行结果会是什么呢?

class Date
{
public:
	Date(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	void Print()
	{
		cout << "Print()" << endl;
		cout << "year:" << _year << endl;
		cout << "month:" << _month << endl;
		cout << "day:" << _day << endl << endl;
	}
	void Print() const
	{
		cout << "Print()const" << endl;
		cout << "year:" << _year << endl;
		cout << "month:" << _month << endl;
		cout << "day:" << _day << endl << endl;
	}
private:
	int _year; // 年
	int _month; // 月
	int _day; // 日
};

void Test()
{
	Date d1(2022, 1, 13);
	d1.Print();
	const Date d2(2022, 1, 13);
	d2.Print();
}

int main()
{
	Test();
	return 0;
}

在解答之前,博主请读者们思考以下几个问题:

1. const对象可以调用非const成员函数吗?
2. 非const对象可以调用const成员函数吗?
3. const成员函数内可以调用其它的非const成员函数吗?
4. 非const成员函数内可以调用其它的const成员函数吗?

        解答上面的这几个问题就涉及到权限的概念(注意:在函数参数传递以及返回过程中,权限的概念只是在引用和指针之间进行讨论),为了让读者们能再次巩固这一块的知识,大家可以阅读我以前写的这一讲的知识:

C++基础精讲篇第2讲:函数重载+引用_King_lm_Guard的博客-CSDN博客https://blog.csdn.net/King_lm_Guard/article/details/125714932?spm=1001.2014.3001.5501现在我来提供结果:

1、不可以,权限被放大了;

2、可以,相当于权限缩小了,权限缩小是被允许的;

3、不能,权限被放大了;

4、可以,权限缩小了。

上述程序结果原理示意:


 知识补充:const修饰指针有分为两种方式,组合有三种形式

1、指针变量不能被修改;

2、指针变量指向的内容不能被修改

 *第一种场景:这里的const表示this指针变量不能被修改;

 *第二种场景:这里的const表示this指针变量指向的内容不能被修改;

 *第三种场景:this指针变量不能被修改的同时,this指针指向的内容也不能被修改。

 建议大家:如果this指针及指针指向得内容均不想被修改时,加上const修饰。

 5、取地址及const取地址操作符重载

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

用法示例


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

6、运算符重载注意事项

1、不能通过连接其他符号来创建新的操作符:比如operator@;
2、重载操作符必须有一个类类型参数;
3、用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不 能改变其含义;
4、作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this;
5、.* :: sizeof ?: . 注意以上5个运算符不能重载。这个经常在笔试选择题中出现。

7、结语

        今天这一讲主要将类中6个默认的成员函数种剩下的三个成员函数进行讲解,其中,赋值运算符重载函数是非常重要的,对于深入学习C++而言,这是必须掌握的,为此在下一讲中,博主将以日期类为例,将各个函数的运用用实例说话,让读者们能理解得更透彻。欢迎点赞、关注、支持!!!

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值