探索C++赋值运算符重载的内部机制:手把手教你精通

这篇具有很好参考价值的文章主要介绍了探索C++赋值运算符重载的内部机制:手把手教你精通。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

探索C++赋值运算符重载的内部机制:手把手教你精通,C++,c++,开发语言


W...Y的主页 😊

代码仓库分享💕 

探索C++赋值运算符重载的内部机制:手把手教你精通,C++,c++,开发语言


🍔前言:

探索C++赋值运算符重载的内部机制:手把手教你精通,C++,c++,开发语言

前一篇博客中我们已经了解并学习了初始化和清理模块中的构造函数与析构函数,还有拷贝复制中的拷贝复制函数,它们都是类与对象中重要的成员,今天我们要来讲一下拷贝复制模块中另一个非常重要的内容——赋值重载,但是在学习赋值重载的同时我们应该先学习运算符重载,话不多说我们直接开始!

目录

赋值运算符重载

运算符重载

 赋值运算符重载


赋值运算符重载

运算符重载

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

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class Date
{
public:
	Date(int year = 1900, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	// Date(const Date& d)  // 正确写法
	void print()
	{
		cout << _year << '/' << _month << '/' << _day << endl;
	}
	Date(const Date& d)  // 错误写法:编译报错,会引发无穷递归
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}

private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1;
	Date d2(2022,10,23);
	int x = 1; 
    int y = 2;
    bool ret = x > y;
	return 0;
}

探索C++赋值运算符重载的内部机制:手把手教你精通,C++,c++,开发语言 上图是比较的反汇编代码,我们可以看出编译器可以直接做出运算符判断。

一般情况下,我们去比较内置类型都非常容易去比较,因为内置类型都是一些基本变量int、char……我们可以直接使用运算符 ==、<、>等等去比较。但是自定义类型我们应该如何处理呢?

一般情况下我们可以自己创建一个比较函数进行比较:

//判断前面日期是否比后面大
//大返回true,小返回false
bool Greater(Date x, Date y)
{
	if (x._year > y._year)
	{
		return true;
	}
	else if (x._year == y._year && x._month > y._month)
	{
		return true;
	}
	else if (x._year == y._year && x._month == y._month && x._day > y._day)
	{
		return true;
	}

	return false;
}

将此函数放入到类中才可以进行私有数据访问,要不就将基本数据公有化!

上述函数可以轻松解决比大小的问题,但是还是有许多缺陷。比如:函数名的不规范就会导致我们不理解函数的作用。所以对于内置类型的比较C++针对起名字做出了一下规定:

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

注意:
不能通过连接其他符号来创建新的操作符:比如operator@
重载操作符必须有一个类类型参数
用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不能改变其含义
作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐
藏的this

.* :: sizeof ?: . 注意以上5个运算符不能重载。这个经常在笔试选择题中出现。 

那针对以上函数我们就可以这样修改:

bool operator>(const Date& x, const Date& y)
{
	if (x._year > y._year)
	{
		return true;
	}
	else if (x._year == y._year && x._month > y._month)
	{
		return true;
	}
	else if (x._year == y._year && x._month == y._month && x._day > y._day)
	{
		return true;
	}

	return false;
}

在参数选择时,我们选择引用而不选择直接传参,这样可以节约时间效率,不用调用拷贝构造函数。 

 这样做我们用户一眼就可以看出此函数的作用,是用来比大小的函数。但是这样去调用函数时函数名还是太长了,而且不直白不美观,所以我们在使用时可以使用非常简单的方式进行调用:

bool ret1 = d1 > d2;

只需要一个运算符就可以调用此函数,是不是非常方便呢!编译器可以帮助我们将这句话转变为,调用函数的语句。

注意:运算符重载与函数重载中都有重载二字,但是绝对是没有任何关系的,函数重载是可以允许参数不同的同名函数,运算符重载是自定义类型可以直接使用运算符。不是姓“张”的都有血缘关系。

但是当我们万事俱备之后进行编译却还是出现报错:探索C++赋值运算符重载的内部机制:手把手教你精通,C++,c++,开发语言 这是为什么呢?

为什么会多一个参数呢?哪里多了?成员参数都会有一个隐藏的参数this指针。所以参数不匹配导致程序出问题。相当于我们在调用函数时使用了两个参数,而设定的参数中却有三个!

我们应该怎么解决问题呢?删一个即可。

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class Date
{
public:
	Date(int year = 1900, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	// Date(const Date& d)  // 正确写法
	void print()
	{
		cout << _year << '/' << _month << '/' << _day << endl;
	}
	//Date(const Date& d)  // 错误写法:编译报错,会引发无穷递归
	//{
	//	_year = d._year;
	//	_month = d._month;
	//	_day = d._day;
	//}
	bool operator>(const Date& y)
	{
		if (_year > y._year)
		{
			return true;
		}
		else if (_year == y._year && _month > y._month)
		{
			return true;
		}
		else if (_year == y._year && _month == y._month && _day > y._day)
		{
			return true;
		}

		return false;
	}

private:
	int _year;
	int _month;
	int _day;
};
//判断日期是否相等
//bool Greater(Date x, Date y)
//bool Compare1(Date x, Date y)


int main()
{
	Date d1;
	Date d2(2022,10,23);
	/*d1 == d2;
	d1 > d2;*/
	bool ret1 = d1 > d2;
	int x = 1, y = 2;
	bool ret = x > y;
	return 0;
}

 我们将参数删除一个即可,编译器看就会转换成d1.operator(d2)在进行转换成d1.operator(&d1,d2)即可,地址就是this指针指向的内容。

我们学明白了运算符重载,那么在进行赋值运算符重载就非常easy了。

 赋值运算符重载

赋值运算符重载格式
参数类型:const T&,传递引用可以提高传参效率
返回值类型:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值
检测是否自己给自己赋值
返回*this :要复合连续赋值的含义

class Date
{
public :
Date(int year = 1900, 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 ;
};

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

class Date
{
public:
Date(int year = 1900, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
int _year;
int _month;
int _day;
};
// 赋值运算符重载成全局函数,注意重载成全局函数时没有this指针了,需要给两个参数
Date& operator=(Date& left, const Date& right)
{
if (&left != &right)
{
left._year = right._year;
left._month = right._month;
left._day = right._day;
}
return left;
}
// 编译失败:
// error C2801: “operator =”必须是非静态成员

原因:赋值运算符如果不显式实现,编译器会生成一个默认的。此时用户再在类外自己实现
一个全局的赋值运算符重载,就和编译器在类中生成的默认赋值运算符重载冲突了,故赋值
运算符重载只能是类的成员函数。探索C++赋值运算符重载的内部机制:手把手教你精通,C++,c++,开发语言 用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝。注
意:内置类型成员变量是直接赋值的,而自定义类型成员变量需要调用对应类的赋值运算符
重载完成赋值

class Time
{
public:
Time()
{
_hour = 1;
_minute = 1;
_second = 1;
}
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
{
private:
// 基本类型(内置类型)
int _year = 1970;
int _month = 1;
int _day = 1;
// 自定义类型
Time _t;
};
int main()
{
Date d1;
Date d2;
d1 = d2;
return 0;
}

既然编译器生成的默认赋值运算符重载函数已经可以完成字节序的值拷贝了,还需要自己实
现吗?当然像日期类这样的类是没必要的。那么下面的类呢?验证一下试试?

// 这里会发现下面的程序会崩溃掉?这里就需要我们以后讲的深拷贝去解决。
typedef int DataType;
class Stack
{
public:
Stack(size_t capacity = 10)
{
_array = (DataType*)malloc(capacity * sizeof(DataType));
if (nullptr == _array)
{
perror("malloc申请空间失败");
return;
}
_size = 0;
_capacity = capacity;
}
void Push(const DataType& data)
{
// CheckCapacity();
_array[_size] = data;
_size++;
}
~Stack()
{
if (_array)
{
free(_array);
_array = nullptr;
_capacity = 0;
_size = 0;
}
}
private:
DataType *_array;
size_t _size;
size_t _capacity;
};
int main()
{
Stack s1;
s1.Push(1);
s1.Push(2);
s1.Push(3);
s1.Push(4);
Stack s2;
s2 = s1;
return 0;
}

 注意:如果类中未涉及到资源管理,赋值运算符是否实现都可以;一旦涉及到资源管理则必
须要实现。

探索C++赋值运算符重载的内部机制:手把手教你精通,C++,c++,开发语言


以上就是赋值运算符重载全部内容!!!感谢大家观看。 文章来源地址https://www.toymoban.com/news/detail-721251.html

到了这里,关于探索C++赋值运算符重载的内部机制:手把手教你精通的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【C++】:拷贝构造函数和赋值运算符重载

    拷贝构造函数是特殊的构造函数。 是用一个已经存在的对象,赋值拷贝给另一个新创建的已经存在的对象 。 本质:用同类型的对象拷贝初始化 。 拷贝构造函数也是 特殊的成员函数 ,其特征如下: 2.1 拷贝构造函数是构造函数的一个重载形式。 2.2 拷贝构造函数的 函数名域

    2024年04月28日
    浏览(44)
  • 【c++】类和对象(五)赋值运算符重载

    🔥个人主页 : Quitecoder 🔥 专栏 : c++笔记仓 朋友们大家好,本篇文章带大家认识赋值运算符重载,const成员,取地址及const取地址操作符重载等内容 运算符重载是一种编程语言特性,它允许开发者为已有的运算符提供自定义的实现。这意味着你可以改变某些运算符在你自定

    2024年04月10日
    浏览(46)
  • C++修炼之筑基期第四层 ——透过日期类看运算符重载 | 赋值运算符重载 | 取地址操作符重载

    🌸作者简介: 花想云 ,在读本科生一枚,致力于 C/C++、Linux 学习。 🌸 本文收录于 C++系列 ,本专栏主要内容为 C++ 初阶、C++ 进阶、STL 详解等,专为大学生打造全套 C++ 学习教程,持续更新! 🌸 相关专栏推荐: C语言初阶系列 、 C语言进阶系列 、 数据结构与算法 本章主要

    2023年04月09日
    浏览(82)
  • 【C++】类和对象(中)---拷贝构造函数、赋值运算符重载

    个人主页:平行线也会相交💪 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 平行线也会相交 原创 收录于专栏【C++之路】💌 本专栏旨在记录C++的学习路线,望对大家有所帮助🙇‍ 希望我们一起努力、成长,共同进步。🍓 拷贝构造函数,又称复制构造函数,是一种特殊的

    2024年02月05日
    浏览(49)
  • 【C++】:类和对象(中)之拷贝构造函数+赋值运算符重载

    在现实生活中,可能存在一个与你一样的自己,我们称其为双胞胎 那在创建对象时,可否创建一个与已存在对象一某一样的新对象呢? 拷贝构造函数:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存在的类类型对象创建新对象时由编译器自动调

    2024年02月06日
    浏览(47)
  • C++ -3- 类和对象 (中) | 拷贝构造函数 & 赋值运算符重载

    示例: 拷贝初始化构造函数的作用是将一个已知对象的数据成员值拷贝给正在创建的另一个同类的对象 无穷递归 ? Date(Date d){……} 首先,分析 传值传参的过程 传引用传参 : 没有拷贝 的过程,直接传 传值传参: 内置类型 编译器可以直接拷贝(浅拷贝/值拷贝——一个字节

    2023年04月19日
    浏览(80)
  • c++类与对象(二)——赋值运算符重载与取地址操作符重载

    前言: 本章将通过 日期类 的实现,深入学习 运算符重载 的实现方法。本章将完成6个默认成员函数中剩余3个—— 赋值运算符重载 与 取地址操作符重载 的学习。 C++ 为了增强代码的可读性引入了 运算符重载 ,运算符重载是具有 特殊函数名 的函数,也具有其返回值类型,

    2024年02月03日
    浏览(44)
  • 【C++】C++入门—初识构造函数 , 析构函数,拷贝构造函数,赋值运算符重载

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

    2024年02月21日
    浏览(50)
  • C++从入门到精通——类的6个默认成员函数之赋值运算符重载

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

    2024年04月25日
    浏览(53)
  • 【C++】类和对象③(类的默认成员函数:拷贝构造函数 | 赋值运算符重载)

    🔥 个人主页: Forcible Bug Maker 🔥 专栏: C++ 目录 前言 拷贝构造函数 概念 拷贝构造函数的特性及用法 赋值运算符重载 运算符重载 赋值运算符重载 结语 本篇主要内容:类的6个默认成员函数中的 拷贝构造函数 和 赋值运算符重载 在上篇文章中我们讲到了类的默认成员函数的

    2024年04月17日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包