【哇! C++】类和对象(五) - 赋值运算符重载
目录
编辑
一、运算符重载
1.1 运算符重载概念
1.2 全局运算符重载
1.3 运算符重载为成员函数
二、赋值运算符重载的特性
2.1 赋值运算符重载需要注意的点
2.2 赋值运算符重载格式
2.2.1 传值返回
2.2.2 传引用返回
2.2.3 检查自己给自己赋值
三、赋值运算符重载的应用
四、总结
一、运算符重载
1.1 运算符重载概念
C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数。也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。
这里虽然用了重载,但是运算符重载和函数重载不是一个东西:
函数重载:允许函数名相同参数不同的函数存在;
运算符重载:让自定义类型的对象可以用运算操作符(必须是C\C++语法存在的运算符)。
函数名字为:关键字operator后面接需要重载的运算符符号。
函数原型:返回值类型 operator 操作符 (参数列表)
1.2 全局运算符重载
使用全局的operator==,程序如下:
#include<iostream>
using namespace std;class Date
{
public:Date(int year = 1, 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;
}int main()
{Date d1(2025, 3, 8);Date d2(2025, 3, 7);cout << (d1 == d2) << endl;//cout << (operator==(d1, d2)) << endl;//两种写法是一样的return 0;
}
上述程序中,全局的运算符重载的形式为:bool operator==(const Date& d1, const Date& d2),这就需要把Date类的成员变量改为私有,即注释掉private。
注:赋值运算符重载成全局函数,注意重载成全局函数时没有this指针了,需要给两个参数。
那么这样操作,就破坏了Date类的封装性。封装性如何保证?
- 使用友元函数;
- 重载为成员函数(常用)。
1.3 运算符重载为成员函数
将上述程序作进一步修改:
#include<iostream>
using namespace std;class Date
{
public:Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = 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 d1(2025, 3, 8);Date d2(2025, 3, 7);cout << (d1 == d2) << endl;cout << d1.operator==(d2) << endl;//两种写法是一样的return 0;
}
运算符重载为成员函数的形式为:bool operator==(const Date& d),这里需要注意的是,左操作数是this,指向调用函数的对象。
1.4 运算符重载需要注意的点
运算符重载的使用需要注意一下5点:
1. 不能通过连接其他符号来创建新的操作符:比如operator@;
2. 重载操作符必须有一个类类型参数;
3. 用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不 能改变其含义;
4. 作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐
藏的this;
5. .* : : sizeof ?: . 注意以上5个运算符不能重载。
针对5中的.*,可以写如下程序:
class ob
{
public:void func(){cout << "void func()" << endl;}
};typedef void(ob::*pobfunc)()int main()
{pobfunc p = &ob::func;//成员函数取地址,要用&操作符,不然取不到//等同于void (ob:: *pi)() = &ob::func;ob tmp;(tmp.*p)();//通过对象去调用成员函数的指针,成员函数指针要传this//*p();//普通的函数指针的调用return 0;
}
函数指针和数组指针都是特殊的指针,普通变量的重命名为:typedef 类型 重命名
上述程序中,typedef void(ob::*pobfunc)()是成员函数指针类型的重定义。其中,pobfunc是指向ob类中成员函数的函数指针类型。
1. void (ob*::)()
函数指针类型,它指向一个返回值为void,且没有参数的成员函数。ob*::表示函数指针指向ob类的成员函数。
2. typedef void(ob*::pobfunc)()
使用typedef关键字重定义一个指向ob类中的成员函数的函数指针类型pobfunc。
二、赋值运算符重载
2.1 赋值运算符重载格式
- 参数类型:const Date&,传递引用可以提高传参效率;
- 返回值类型:Date&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值;
- 检测是否自己给自己赋值;
- 返回*this :要复合连续赋值的含义。
相较于传值传参和传引用传参。
2.1.1 传值返回
将1.3的程序在Date类中进行补充,补充的程序为:
Date operator=(const Date& d2)
{this->_year = d2._year;this->_month = d2._month;this->_day = d2._day;return *this;//*this就是d1,相当于拿到左操作数
}
因为,Date operator=(const Date& d)中的Date表明是传值返回,意味着return *this;不会返回*this,而是返回它的拷贝(拷贝以后或存放在寄存器中)。
所以,同类型的传值拷贝又会调用一个拷贝构造。
2.1.2 传引用返回
将1.3的程序在Date类中进行补充,补充的程序为:
Date& operator=(const Date& d2)
{this->_year = d2._year;this->_month = d2._month;this->_day = d2._day;return *this;//*this就是d1,相当于拿到左操作数
}
2.1.3 检查自己给自己赋值
这可能会造成性能的浪费;成员变量可能依赖于其他成员变量的值,如果这些成员变量的值被覆盖,可能会引发错误。
基于2.2.2,可通过判断地址来进一步改写:
Date& operator=(const Date& d2)
{if(this != &d2){this->_year = d2._year;this->_month = d2._month;this->_day = d2._day;}return *this;
}
2.2 赋值运算符只能重载成类的成员函数
C++规定,其他运算符可以重载成全局的,赋值重载不可以,只能重载为成员函数。
对于默认成员函数,如果不写,编译器会生成一份。如果放在全局,类中没有,编译器会生成一份,那调用的时候会产生冲突。
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 =”必须是非静态成员
2.3 没有显式,编译器会生成一个默认赋值运算符重载
不写赋值运算符重载,编译器会不会生成默认的呢? - 会,因为是6个默认成员函数之一。
默认生成的对内置类型会完成值拷贝(浅拷贝),对自定义类型会去再调用它的赋值。
怎么知道赋值默认生成的赋值的行为是什么? - 同拷贝构造。
那是不是意味着自定义赋值操作符重载就可以不写了呢? - 不是。
注意:如果类中未涉及到资源管理,赋值运算符是否实现都可以;一旦涉及到资源管理则必
须要实现。
三、赋值运算符重载的应用
如果是内置类型,编译器是可以调用相关指令的;如果是自定义类型,编译器首先会去看有没有重载运算符,如果没有就会报错。
#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& operator=(const Date& d){if(this != &d){this->_year = d._year;this->_month = d._month;this->_day = d._day;}return *this;}Print(){cout << _year << "-" << _month << "-" << _day << endl;}private:int _year;int _month;int _day;
};int main()
{Date d1(2025, 3, 9);Date d2(2025, 3, 9);d1 = d2;Date d3(d1);d1 = d2 = d3;//自定义类型,连续赋值是要有返回值的d3.Print();int i, j = 0;cout << (i = j = 10) << endl;return 0;
}
程序Date d3(d1);为拷贝构造,还是一个构造。构造是指对象创建实例化的时候自动调用的初始化。其他的构造可能是用一些普通的参数进行初始化,而拷贝构造是用同类型一个存在的对象进行初始化要创建的对象。
程序d1 = d2;,已经存在的两个对象,一个拷贝赋值给另一个,这里边用到了=运算符,所以就要重载这个运算符。
程序d1 = d2 = d3;为自定义类型,连续赋值是要有返回值的。
程序i = j = 10;,内置类型支持连续赋值。执行动作为:10赋值给j作为一个表达式,这个表达式有返回值,返回值就是左操作数j。同理,再向左,返回值为左操作数i。
四、总结
默认生成的函数行为总结:
- 构造和析构:内置类型不处理,自定义类型调用对应的构造和析构。
- 拷贝构造和赋值运算符重载:内置类型值拷贝,自定义类型调用对应的拷贝构造和赋值重载。
相关文章:

【哇! C++】类和对象(五) - 赋值运算符重载
目录 编辑 一、运算符重载 1.1 运算符重载概念 1.2 全局运算符重载 1.3 运算符重载为成员函数 二、赋值运算符重载的特性 2.1 赋值运算符重载需要注意的点 2.2 赋值运算符重载格式 2.2.1 传值返回 2.2.2 传引用返回 2.2.3 检查自己给自己赋值 三、赋值运算符重载的…...

SpringCloud系列教程(十三):Sentinel流量控制
SpringCloud中的注册、发现、网关、服务调用都已经完成了,现在就剩下最后一部分,就是关于网络控制。SpringCloud Alibaba这一套中间件做的非常好,把平时常用的功能都集成进来了,而且非常简单高效。我们下一步就完成最后一块拼图Se…...

vue+element|el-tree树设置懒加载和设置默认勾选
文章目录 导文代码实现1. 基本结构2. 懒加载实现3. 默认勾选功能4. 动态加载初始节点5. 节点勾选事件监听完整代码 导文 在实际开发中,很多数据过于庞大,需要分批请求,使用到懒加载。但是在tree的方法中,使用懒加载后无法直接使用…...
零售交易流程相关知识(top-down拆解)
引入 关于POS机交易时的后台数据交互 模块之间数据交换,都可以能被窃取或篡改。由此引入加密、解密机制和签名、验签机制 经典的加密、解密机制: 对称加密:DES\ TDES\ AES\ RC4 非对称加密:RSA\ DSA\ ECC 经典的签名、验签…...

混合存储HDD+SSD机型磁盘阵列,配上SSD缓存功能,性能提升300%
企业日常运行各种文件无处不在,文档、报告、视频、应用数据......面对成千上万的文件,团队之间需要做到无障碍协作,员工能够即时快速访问、共享处理文件。随着业务增长,数字化办公不仅需要大容量,快速高效的文件访问越…...
将本地已有的项目上传至仓库
上传的仓库为Gitee 进入项目目录: 使用命令行工具进入你想要上传的项目的根目录。 初始化Git仓库: 如果项目目录尚未初始化为Git仓库,执行以下命令: git init 执行完成后,项目根目录下会自动生成一个隐藏的.git文件夹…...
中级网络工程师面试题参考示例(3)
一、企业园区网络 问题1:如何实现园区网络的自动化部署和管理?请结合实际场景说明技术选型。 答案要点: 技术选型: SDN(软件定义网络):通过控制器(如Cisco DNA Center)…...

祝福语【算法赛】
题目来源:第 27 场 蓝桥入门赛【算法题】 可以参考一下,本人也是比较菜 不喜勿喷,求求求 import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner sc new Scanner(System.in);String S sc.nextLi…...

前端 | CORS 跨域问题解决
问题:Access to fetch at http://localhost:3000/save from origin http://localhost:5174 has been blocked by CORS policy: Response to preflight request doesnt pass access control check: No Access-Control-Allow-Origin header is present on the request…...
MySQL知识点(第一部分)
MySQL 基础: 1、SQL语句的分类: DDL:用于控制数据库的操作DML:用于控制表结构的字段,增、删、修DQL:用于查询语句DCL:用于管理数据库,用户,数据库的访问 权限。 2、M…...
ChatGPT使用经验分享
ChatGPT 3.5模型 与 4模型的区别 ChatGPT 3.5 示例 问:树上有9只鸟,打死了一只还剩几只? 答:如果打死了一只鸟,那么树上还剩下8只鸟。 ChatGPT 4 示例 问:树上有9只鸟,打死了一只还剩几只&…...
Webshell原理与利用
本文内容仅用于技术研究、网络安全防御及合法授权的渗透测试,严禁用于任何非法入侵、破坏或未经授权的网络活动。 1. WebShell的定义与原理 定义:WebShell是一种基于Web脚本语言(如PHP、ASP、JSP)编写的恶意后门程序,…...
Java直通车系列15【Spring MVC】(ModelAndView 使用)
目录 1. ModelAndView 概述 2. ModelAndView 的主要属性和方法 主要属性 主要方法 3. 场景示例 示例 1:简单的 ModelAndView 使用 示例 2:使用 ModelAndView 处理列表数据 示例 3:使用 ModelAndView 处理异常情况 1. ModelAndView 概…...

大模型系列课程学习-基于Vllm/Ollama/Ktransformers完成Deepseek推理服务部署
1.机器配置及实验说明 基于前期搭建的双卡机器装机教程,配置如下: 硬件名称参数备注CPUE5-2680V42 *2(线程28个)无GPU2080TI-22G 双卡魔改卡系统WSL Unbuntu 22.04.5 LTS虚拟机 本轮实验目的:基于VLLM/Ollama/ktran…...

基于深度文档理解的开源 RAG 引擎RAGFlow的介绍和安装
目录 前言1. RAGFlow 简介1.1 什么是 RAGFlow?1.2 RAGFlow 的核心特点 2. RAGFlow 的安装与配置2.1 硬件与软件要求2.2 下载 RAGFlow 源码2.3 源码编译 Docker 镜像2.4 设置完整版(包含 embedding 模型)2.5 运行 RAGFlow 3. RAGFlow 的应用场…...
DNS Beaconing
“DNS Beaconing” 是一种隐蔽的网络通信技术,通常与恶意软件(如木马、僵尸网络)相关。攻击者通过定期发送 DNS请求 到受控的域名服务器(C&C服务器),实现与恶意软件的隐蔽通信、数据传输或指令下发。由…...

【论文阅读】多模态——LSeg
文献基本信息 标题:Language-Driven Semantic Segmentation作者:Boyi Li、Kilian Q. Weinberger、Serge Belongie、Vladlen Koltun、Ren Ranftl单位:Cornell University、University of Copenhagen、Apple、Intel Labs会议/期刊:…...

vue3如何配置环境和打包
很多新手友友们或刚从vue2切换到vue3的同学,对vue3不同环境配置和打包有很多困惑的地方,Jenna这就把vue3打包配置流程详细的写下来,你们只需要copy就好啦 1.创建环境文件 当我们把项目拿到手,只需要创建三个环境文件:…...
高并发下订单库存防止超卖策略
文章目录 什么是超卖问题?推荐策略:Redis原子操作(Redis incr)乐观锁lua脚本利用Redis increment 的原子操作,保证库存数安全update使用乐观锁LUA脚本保持库存原子性 什么是超卖问题? 在并发的场景下,比如商城售卖商品…...

vue安装stylelint
执行 npm install -D stylelint postcss-html stylelint-config-recommended-vue stylelint-config-standard stylelint-order stylelint-prettier postcss-less stylelint-config-property-sort-order-smacss 安装依赖,这里是less,sass换成postcss-scss…...
【杂谈】-递归进化:人工智能的自我改进与监管挑战
递归进化:人工智能的自我改进与监管挑战 文章目录 递归进化:人工智能的自我改进与监管挑战1、自我改进型人工智能的崛起2、人工智能如何挑战人类监管?3、确保人工智能受控的策略4、人类在人工智能发展中的角色5、平衡自主性与控制力6、总结与…...

以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:
一、属性动画概述NETX 作用:实现组件通用属性的渐变过渡效果,提升用户体验。支持属性:width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项: 布局类属性(如宽高)变化时&#…...

安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件
在选煤厂、化工厂、钢铁厂等过程生产型企业,其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进,需提前预防假检、错检、漏检,推动智慧生产运维系统数据的流动和现场赋能应用。同时,…...
JVM垃圾回收机制全解析
Java虚拟机(JVM)中的垃圾收集器(Garbage Collector,简称GC)是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象,从而释放内存空间,避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...
C++.OpenGL (10/64)基础光照(Basic Lighting)
基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...

(转)什么是DockerCompose?它有什么作用?
一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用,而无需手动一个个创建和运行容器。 Compose文件是一个文本文件,通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...

Mac下Android Studio扫描根目录卡死问题记录
环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中,提示一个依赖外部头文件的cpp源文件需要同步,点…...

20个超级好用的 CSS 动画库
分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码,而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库,可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画,可以包含在你的网页或应用项目中。 3.An…...
C++课设:简易日历程序(支持传统节假日 + 二十四节气 + 个人纪念日管理)
名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、为什么要开发一个日历程序?1. 深入理解时间算法2. 练习面向对象设计3. 学习数据结构应用二、核心算法深度解析…...
CSS | transition 和 transform的用处和区别
省流总结: transform用于变换/变形,transition是动画控制器 transform 用来对元素进行变形,常见的操作如下,它是立即生效的样式变形属性。 旋转 rotate(角度deg)、平移 translateX(像素px)、缩放 scale(倍数)、倾斜 skewX(角度…...