C++入门系列-赋值运算符重载

🌈个人主页:羽晨同学 

💫个人格言:“成为自己未来的主人~”  

赋值运算符重载

运算符重载

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

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

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

注意:

  • 不能通过连接其他符号来创建新的操作符,比如operator@,这个其实完全没意义。
  • 重载操作符必须有一个类类型参数,这个就证明了重载操作符是针对自定义类型的,不可能针对内置类型。
  • 用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不能改变其含义。
  • 作为类成员函数重载时,其形参看起来比操作数少一,因为有一个隐藏的this指针。
  • .*   ::  sizeof  ?:   .这五个运算符是不能重载的。

接下来我们先来讲讲这五个不能重载的运算符中的第一个。这个运算符是极其少见的。

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
class OB
{
public:void func(){cout << "void func()" << endl;}
};
typedef void(OB::* PtrFunc)();int main()
{PtrFunc fp = &OB::func;//成员函数取地址要加一个&,普通函数函数名就是地址OB temp;(temp.*fp)();return 0;
}

其实.*的作用是什么呢,我们可以通过这段代码看到,.*的作用就是帮助我们调用成员函数的指针。

 接下来,我们就回到了operator关键字的作用,这个关键字可以极大的提高代码的可读性,我们来看下面的代码。

class Date
{
public:Date(int year = 1900, int month = 1, int day = 1){_year = year;_month = month;_day = day;}
private:int _year;int _month;int _day;
};
bool operator==(const Date& d1, const Date& d2)
{return d1._year == d2._year&& d1._month == d2._month&& d1._day == d2._day;
}
void Test()
{Date d1(2018,9.26);Date d2(2018, 9, 27);cout << (d1 == d2) << endl;
}

这段代码是operator的全局调用,我们会看到如果全局调用的话会存在一个问题,那就是成员变量是私有的。我们无法保证封装性。

这里的解决办法有三种,

  1.  提供这些成员的get和set
  2. 友元 
  3. 重载为成员函数

我们一般使用的就是第三种。重载为成员函数

什么意思呢?我们来看下面的这段代码

class Date
{
public:Date(int year = 1900, int month = 1, int day = 1){_year = year;_month = month;_day = day;}bool Func(const Date& d){return this->_year == d._year&& this->_month == d._month&& this->_day == d._day;}bool operator==(const Date& d){return this->_year == d._year&& this->_month == d._month&& this->_day == d._day;}
private:int _year;int _month;int _day;
};
int main()
{Date d3(2024, 4, 14);Date d4(2024, 4, 15);cout << d3.operator==(d4) << endl;cout << (d3 == d4) << endl;return 0;
}

 懂了吗,我们将重载函数放到成员函数里面,就避免了权限不够的问题。

赋值运算符重载

赋值运算符重载格式

  • 参数类型:const T&,传递引用可以提高传参效率。
  • 返回值类型: T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续复制
  • 检测是否自己给自己复制
  • 返回*this,要复合连续赋值的含义。
#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){cout << "	Date(const Date& d)" << endl;_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;}void Print(){cout << _year << "-" << _month << "-" << _day << endl;}~Date(){cout << "~Date()" << endl;_year = -1;_month = -1;_day = -1;}
private:int _year;int _month;int _day;
};int main()
{Date d1(2024, 4, 14);Date d2(d1);Date d3 = d1;return 0;
}

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

这个怎么理解呢?其实重载成类的成员函数和重载成全局函数有一个很大的不同点,就是成员函数还有一个潜在的this指针,而全局函数是没有这个东西,所以,如果要重载为全局函数的话,我们就需要给两个参数。

class Date
{
public:Date(int year = 1949, int month = 10, int day = 1){_year = year;_month = month;_day = day;}
private:int _year;int _month;int _day;
};Date& operator=(Date& left, const Date& right)
{if (&left != &right){left._year = right._year;left._month = right._month;left._day = right._day;}return left;
}

我们发现这个代码是会报错的, 原因是由于赋值运算符如果不显示实现,编译器会生成一个默认的。此时用户再在类外自己实现一个全局的赋值运算符重载,就和编译器在类中编译器自己生成的默认赋值运算符重载冲突了,故赋值运算符重载只能是类的成员函数。

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

class Date
{
public:Date(int year = 2024, int month = 3, int day = 4){_year = year;_month = month;_day = day;}
private:int _month;int _day;int _year;
};
int main()
{Date d1(2024, 5, 15);Date d2;d2 = d1;return 0;
}
#include<iostream>
using namespace std;
class Time
{
public:private:int _hour = 1;int _second = 1;int _minute = 1;
};
class Date
{
public:void Print(){cout << "class Time" << endl;}Date(int year = 2024, int month = 3, int day = 4){_year = year;_month = month;_day = day;}
private:int _month;int _day;int _year;Time _t;
};
int main()
{Date d1(2024, 5, 15);Date d2;d2 = d1;d1.Print();d2.Print();return 0;
}

 

通过这个结果,我们可以很明显的得出上面的结论。

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/13222.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用React.createContext()在React应用中传递数据,nolan出品

React.createContext() 是React中的一个API&#xff0c;用于创建一个“上下文”&#xff0c;这是一种在组件树中传递数据的方法&#xff0c;而无需手动将props逐级传递。 这个方法接受一个参数&#xff0c;即默认值&#xff0c;当组件在树中上层没有找到对应的Provider时&…

【GESP试卷】2024年03月Scratch三级试卷

2024年GESP03月认证Scratch三级试卷 分数&#xff1a;100 题数&#xff1a;27 一、单选题(共15题&#xff0c;每题2分&#xff0c;共30分) 010203040506070809101112131415CBACADDADCBCBAB 1、小杨的父母最近刚刚给他买了一块华为手表&#xff0c;他说手表上跑的是鸿蒙&…

24长三角A题思路+分析选题

需要资料的宝子们可以进企鹅获取 A题 问题1&#xff1a;西湖游船上掉落华为 mate 60 pro 手机 1. 手机掉落范围分析 物品特征&#xff1a;华为 mate 60 pro 手机的尺寸、重量、形状等特性。静水假设&#xff1a;西湖水面平静&#xff0c;不考虑水流影响。掉落位置&#xff…

在C#语言里对NULL的技术处理

文章目录 前言1 、NULL合并操作符&#xff08;??&#xff09;2. 条件运算符 (?:)3. 空条件运算符(?.)4. 空合并赋值操作符 (??)5. 宽容运算符 (!.)6. 使用 is 运算符7. ArgumentNullException 参数空异常结论 前言 在 C# 中&#xff0c;null 是一个特殊存在&#xff0c;…

安卓Fragment基础

目录 前言一、基础使用二、动态添加Fragment三、Fragment的生命周期四、Fragment之间进行通信五、Fragment兼容手机和平板示例 前言 Fragment基础使用笔记 一、基础使用 Activity布局和文件 <LinearLayout xmlns:android"http://schemas.android.com/apk/res/andro…

OpenAI 发布 GPT-4o,再次巩固行业地位!

5 月 14 日凌晨 1 点&#xff08;太平洋时间上午 10 点&#xff09;&#xff0c;OpenAI 发布了其最新的 GPT-4o&#xff0c;再次巩固了其在人工智能领域的领导地位。这次发布不仅仅是一个产品的推出&#xff0c;更是向世界宣告 AI 技术已迈入一个全新的纪元。OpenAI 的 CEO 萨姆…

品牌窜货治理管控的方法

窜货问题确实是一个需要品牌方高度关注和有效治理的难题。这种现象通常源于品牌区域销售政策的差异&#xff0c;经销商为了获取更多的利润&#xff0c;往往会利用这些差异进行跨区域的低价销售。这不仅损害了大多数经销商的利益&#xff0c;也破坏了市场的稳定和品牌价值。 品牌…

深入理解 Spring 循环依赖之三级缓存(附源码分析)

前言&#xff1a; 学过 Spring 的都知道 Spring 利用三级缓存解决了循环依赖问题&#xff0c;那你知道什么是循环依赖&#xff1f;什么又是三级缓存&#xff1f;本篇将从源码层面分析 Spring 是怎么去利用三级缓存帮我们解决循环依赖问题。 深入理解 Spring IOC 底层实现机制…

三生随记——丽水诡事

在浙江的深山之中&#xff0c;隐藏着一座名为丽水的古老小城。这里山水秀丽&#xff0c;风景如画&#xff0c;但在这美丽的外表下&#xff0c;却隐藏着不为人知的恐怖秘密。 传闻&#xff0c;丽水的郊外有一片被诅咒的竹林。这片竹林与其他竹林不同&#xff0c;它的叶子常年枯黄…

c# datagridview基本操作,包括行拖拽,添加自定义行列。

项目场景&#xff1a; 这段代码定义了一个名为 ucDatagridviewHelper 的用户控件&#xff08;UserControl&#xff09;&#xff0c;该控件包含了一个 DataGridView 控件和一些其他功能。 这段代码的主要部分&#xff1a; 构造函数&#xff1a;在构造函数中&#xff0c;初始化…

C++ | Leetcode C++题解之第89题格雷编码

题目&#xff1a; 题解&#xff1a; class Solution { public:vector<int> grayCode(int n) {vector<int> ret(1 << n);for (int i 0; i < ret.size(); i) {ret[i] (i >> 1) ^ i;}return ret;} };

数据结构--红黑树(RBTree)

一、红黑树概念 1.1 什么是红黑树 红黑树&#xff0c;是一种二叉搜索树&#xff0c;但在每个结点上增加一个存储位表示结点的颜色&#xff0c;可以是Red或 Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制&#xff0c;红黑树确保没有一条路径会比其他路径长…

openEuler-22.03-LTS安装opengauss5.0.1(包含cm集群管理)主备

环境说明 openEuler-22.0.3-LTS opengauss5.0.1 安装数据库 安装系统依赖包 yum -y install lksctp* yum -y install psmisc yum -y install bzip2 yum -y install unzip yum -y install gcc yum -y install gcc-c yum -y install perl yum -y install libxml2-devel yum …

前端(包含cocosCreator)开发环节调取后端接口时跨域,解决办法之反向代理

/** eslint-disable */ var http require(http),httpProxy require(http-proxy),HttpProxyRules require(http-proxy-rules);// Set up proxy rules instance var port 9090 var proxyRules new HttpProxyRules({rules: {/api/(.*): https://baidu.com/$1, // 测试环境游戏…

自学VBA 设置单元格文字格式 笔记

一.设定对应单元格对应需要显示的格式 Cells(1, 1).Font.Size 18 字体大小 Cells(1, 2).Font.Color RGB(255, 0, 0) 字体颜色 Cells(1, 3).Font.Name "黑体" 字体类型 Cells(1, 4).Font.Italic True 字体斜体 Cells(1, 5).Font.FontStyle "BOLD"…

ubuntu下gcc编译器的安装

.gcc编译器的安装 一般linux下是覆盖含有的&#xff0c;如果没有执行更新命令 sudo apt update gcc安装成功&#xff0c;可以检查一下版本 可以看出我的gcc是9.4.0版本的

验证torch.nn.Conv2d

import os import cv2 import torch import numpy as np import random import cv2 as cv from matplotlib import pyplot as pltdef f_VerifyConv2D():"""验证torch.nn.Conv2d&#xff0c; 并将输入数据及权重保存到txt文件中"""x torch.randn…

SpringBoot环境隔离Profiles

前言 通常我们开发不可能只有一个生产环境&#xff0c;还会有其它的开发&#xff0c;测试&#xff0c;预发布环境等等。为了更好的管理每个环境的配置项&#xff0c;springboot也提供了对应的环境隔离的方法。 直接上干货 知识点 激活环境方法 1&#xff0c;在application…

专用设备制造业供应商收发文件,有什么专业而轻便的方式吗?

专用设备制造业的特点包括&#xff1a;门类广、跨度大、科技含量高。它主要生产的是国民经济各部门&#xff08;包括采掘、化工、冶炼、能源、医疗卫生、环保等&#xff09;所急需的重大成套设备&#xff0c;例如矿产资源井采及露天开采设备、大型火电、水电、核电成套设备、石…

教育行业文本短信VS视频短信VS语音短信哪个好?

在教育行业中&#xff0c;文本短信、视频短信和语音短信各有其优势&#xff0c;选择哪种方式更好取决于具体的应用场景和目标。 文本短信的优势在于&#xff1a; 1.简洁明了&#xff1a;能够快速、直接地传递信息&#xff0c;对于需要快速通知或提醒的场景非常适用。 …