当前位置: 首页 > news >正文

【哇! 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. 使用友元函数;
  2. 重载为成员函数(常用)。

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中的注册、发现、网关、服务调用都已经完成了&#xff0c;现在就剩下最后一部分&#xff0c;就是关于网络控制。SpringCloud Alibaba这一套中间件做的非常好&#xff0c;把平时常用的功能都集成进来了&#xff0c;而且非常简单高效。我们下一步就完成最后一块拼图Se…...

vue+element|el-tree树设置懒加载和设置默认勾选

文章目录 导文代码实现1. 基本结构2. 懒加载实现3. 默认勾选功能4. 动态加载初始节点5. 节点勾选事件监听完整代码 导文 在实际开发中&#xff0c;很多数据过于庞大&#xff0c;需要分批请求&#xff0c;使用到懒加载。但是在tree的方法中&#xff0c;使用懒加载后无法直接使用…...

零售交易流程相关知识(top-down拆解)

引入 关于POS机交易时的后台数据交互 模块之间数据交换&#xff0c;都可以能被窃取或篡改。由此引入加密、解密机制和签名、验签机制 经典的加密、解密机制&#xff1a; 对称加密&#xff1a;DES\ TDES\ AES\ RC4 非对称加密&#xff1a;RSA\ DSA\ ECC 经典的签名、验签…...

混合存储HDD+SSD机型磁盘阵列,配上SSD缓存功能,性能提升300%

企业日常运行各种文件无处不在&#xff0c;文档、报告、视频、应用数据......面对成千上万的文件&#xff0c;团队之间需要做到无障碍协作&#xff0c;员工能够即时快速访问、共享处理文件。随着业务增长&#xff0c;数字化办公不仅需要大容量&#xff0c;快速高效的文件访问越…...

将本地已有的项目上传至仓库

上传的仓库为Gitee 进入项目目录&#xff1a; 使用命令行工具进入你想要上传的项目的根目录。 初始化Git仓库&#xff1a; 如果项目目录尚未初始化为Git仓库&#xff0c;执行以下命令&#xff1a; git init 执行完成后&#xff0c;项目根目录下会自动生成一个隐藏的.git文件夹…...

中级网络工程师面试题参考示例(3)

一、企业园区网络 问题1&#xff1a;如何实现园区网络的自动化部署和管理&#xff1f;请结合实际场景说明技术选型。 答案要点&#xff1a; 技术选型&#xff1a; SDN&#xff08;软件定义网络&#xff09;&#xff1a;通过控制器&#xff08;如Cisco DNA Center&#xff09;…...

祝福语【算法赛】

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

前端 | CORS 跨域问题解决

问题&#xff1a;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 基础&#xff1a; 1、SQL语句的分类&#xff1a; DDL&#xff1a;用于控制数据库的操作DML&#xff1a;用于控制表结构的字段&#xff0c;增、删、修DQL&#xff1a;用于查询语句DCL&#xff1a;用于管理数据库&#xff0c;用户&#xff0c;数据库的访问 权限。 2、M…...

ChatGPT使用经验分享

ChatGPT 3.5模型 与 4模型的区别 ChatGPT 3.5 示例 问&#xff1a;树上有9只鸟&#xff0c;打死了一只还剩几只&#xff1f; 答&#xff1a;如果打死了一只鸟&#xff0c;那么树上还剩下8只鸟。 ChatGPT 4 示例 问&#xff1a;树上有9只鸟&#xff0c;打死了一只还剩几只&…...

Webshell原理与利用

本文内容仅用于技术研究、网络安全防御及合法授权的渗透测试&#xff0c;严禁用于任何非法入侵、破坏或未经授权的网络活动。 1. WebShell的定义与原理 定义&#xff1a;WebShell是一种基于Web脚本语言&#xff08;如PHP、ASP、JSP&#xff09;编写的恶意后门程序&#xff0c;…...

Java直通车系列15【Spring MVC】(ModelAndView 使用)

目录 1. ModelAndView 概述 2. ModelAndView 的主要属性和方法 主要属性 主要方法 3. 场景示例 示例 1&#xff1a;简单的 ModelAndView 使用 示例 2&#xff1a;使用 ModelAndView 处理列表数据 示例 3&#xff1a;使用 ModelAndView 处理异常情况 1. ModelAndView 概…...

大模型系列课程学习-基于Vllm/Ollama/Ktransformers完成Deepseek推理服务部署

1.机器配置及实验说明 基于前期搭建的双卡机器装机教程&#xff0c;配置如下&#xff1a; 硬件名称参数备注CPUE5-2680V42 *2&#xff08;线程28个&#xff09;无GPU2080TI-22G 双卡魔改卡系统WSL Unbuntu 22.04.5 LTS虚拟机 本轮实验目的&#xff1a;基于VLLM/Ollama/ktran…...

基于深度文档理解的开源 RAG 引擎RAGFlow的介绍和安装

目录 前言1. RAGFlow 简介1.1 什么是 RAGFlow&#xff1f;1.2 RAGFlow 的核心特点 2. RAGFlow 的安装与配置2.1 硬件与软件要求2.2 下载 RAGFlow 源码2.3 源码编译 Docker 镜像2.4 设置完整版&#xff08;包含 embedding 模型&#xff09;2.5 运行 RAGFlow 3. RAGFlow 的应用场…...

DNS Beaconing

“DNS Beaconing” 是一种隐蔽的网络通信技术&#xff0c;通常与恶意软件&#xff08;如木马、僵尸网络&#xff09;相关。攻击者通过定期发送 DNS请求 到受控的域名服务器&#xff08;C&C服务器&#xff09;&#xff0c;实现与恶意软件的隐蔽通信、数据传输或指令下发。由…...

【论文阅读】多模态——LSeg

文献基本信息 标题&#xff1a;Language-Driven Semantic Segmentation作者&#xff1a;Boyi Li、Kilian Q. Weinberger、Serge Belongie、Vladlen Koltun、Ren Ranftl单位&#xff1a;Cornell University、University of Copenhagen、Apple、Intel Labs会议/期刊&#xff1a;…...

vue3如何配置环境和打包

很多新手友友们或刚从vue2切换到vue3的同学&#xff0c;对vue3不同环境配置和打包有很多困惑的地方&#xff0c;Jenna这就把vue3打包配置流程详细的写下来&#xff0c;你们只需要copy就好啦 1.创建环境文件 当我们把项目拿到手&#xff0c;只需要创建三个环境文件&#xff1a…...

高并发下订单库存防止超卖策略

文章目录 什么是超卖问题&#xff1f;推荐策略&#xff1a;Redis原子操作(Redis incr)乐观锁lua脚本利用Redis increment 的原子操作&#xff0c;保证库存数安全update使用乐观锁LUA脚本保持库存原子性 什么是超卖问题&#xff1f; 在并发的场景下&#xff0c;比如商城售卖商品…...

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 安装依赖&#xff0c;这里是less&#xff0c;sass换成postcss-scss…...

告别tmpfs和ramfs:自己动手写一个极简内存文件系统,深入理解VFS与Page Cache

从零构建内存文件系统&#xff1a;深入VFS与Page Cache的工程实践 在Linux系统中&#xff0c;内存文件系统&#xff08;Memory File System&#xff09;因其卓越的I/O性能而广受开发者青睐。不同于传统磁盘文件系统需要经过块设备层和驱动栈的冗长路径&#xff0c;内存文件系统…...

智能化运维实战:信息化系统自动化巡检与故障自愈方案

1. 为什么需要自动化巡检与故障自愈&#xff1f; 想象一下&#xff0c;你负责维护一个大型电商平台的后台系统。凌晨3点突然收到告警短信&#xff1a;数据库CPU使用率飙升到98%。这时候你需要立刻起床&#xff0c;手忙脚乱地登录服务器检查日志、分析原因、尝试重启服务...这样…...

暗黑破坏神2终极单机插件:PlugY生存工具包完全指南

暗黑破坏神2终极单机插件&#xff1a;PlugY生存工具包完全指南 【免费下载链接】PlugY PlugY, The Survival Kit - Plug-in for Diablo II Lord of Destruction 项目地址: https://gitcode.com/gh_mirrors/pl/PlugY 如果你是一名暗黑破坏神2的单机玩家&#xff0c;是否曾…...

Adafruit MAX44009库详解:超低功耗环境光传感器驱动与工程实践

1. 项目概述Adafruit MAX44009 库是专为 Analog Devices&#xff08;原 Maxim Integrated&#xff09;推出的 MAX44009 环境光传感器设计的 Arduino 兼容驱动库。该库封装了 IC 通信、寄存器配置、自动量程切换、中断管理及光照度&#xff08;lux&#xff09;换算等底层逻辑&am…...

Chatterbox:多语言语音合成的开源解决方案

Chatterbox&#xff1a;多语言语音合成的开源解决方案 【免费下载链接】chatterbox Open source TTS model 项目地址: https://gitcode.com/GitHub_Trending/chatterbox7/chatterbox Chatterbox是一款由Resemble AI开发的开源语音合成&#xff08;TTS&#xff09;模型&a…...

MuJoCo仿真实战:用aubo-i5机器人模型搭建你的第一个物理仿真环境(Windows/Linux双平台)

MuJoCo仿真实战&#xff1a;用aubo-i5机器人模型搭建你的第一个物理仿真环境&#xff08;Windows/Linux双平台&#xff09; 机器人仿真技术正在重塑工业自动化研发流程。想象一下&#xff0c;在投入数百万购置实体设备前&#xff0c;你就能在虚拟环境中验证算法、优化轨迹规划、…...

SpringBoot+Vue实战:手把手教你搭建苍穹外卖后台管理系统(含Nginx配置避坑指南)

SpringBootVue全栈实战&#xff1a;从零构建外卖管理系统与Nginx部署精要 每次打开招聘网站&#xff0c;看到"要求有完整项目经验"的字样时&#xff0c;你是否也感到一阵心虚&#xff1f;作为全栈开发的学习者&#xff0c;我们往往陷入一个怪圈&#xff1a;学了很多碎…...

SteamStub DRM高效移除解决方案:从技术原理到实战应用全流程指南

SteamStub DRM高效移除解决方案&#xff1a;从技术原理到实战应用全流程指南 【免费下载链接】Steamless Steamless is a DRM remover of the SteamStub variants. The goal of Steamless is to make a single solution for unpacking all Steam DRM-packed files. Steamless a…...

原创:黄大年茶思屋难题揭榜第141期|5道核心题精简公开·未获技术反馈求指正

黄大年茶思屋难题揭榜第141期&#xff5c;5道核心题精简公开未获技术反馈求指正 作者&#xff1a;华夏之光永存 摘要 这五道题我们已完整解题并提交黄大年茶思屋难题揭榜&#xff0c;最终被退回&#xff0c;但平台未给出任何具体技术驳回意见、未指明缺陷、未提供修改方向。我们…...

亚马逊 API 签名认证机制详解

在调用亚马逊开放平台、亚马逊云服务&#xff08;AWS&#xff09;各类 API 时&#xff0c;签名认证是请求合法的核心门槛&#xff0c;目前主流采用 Signature Version 4&#xff08;SigV4&#xff09; 签名机制。它通过对请求内容与密钥做加密计算&#xff0c;实现身份校验、防…...