8、操作符重载

友元

  • 可以通过friend关键字,把一个全局函数、另一个类的成员函数或者另一个类整体,声明为授权类的友元
  • 友元拥有访问授权类任何非公有成员的特权
  • 友元声明可以出现在授权类的公有、私有或者保护等任何区域不受访问控制限定符的约束
  • 友元不是成员,其作用域并不隶属于授权类,也不拥有授权类类型的this指针。

操作符标记和操作符函数

双目操作符表达式

L#R

成员函数形式:L.operator#(R)

  • 左操作数是调用对象,右操作数是参数对象

全局函数形式:operator#(L,R)

  • 左操作数是第一个参数,右操作数是第二个参数

单目操作符表达式

#O/O#

  • 成员函数形式:O.operator#()
  • 全局函数形式:operator#(O)

三目操作符表达式: F#S#T

三目操作符无法重载

经典双目操作符

运算类双目操作符:+、-、*、/等

  • 左右操作数均可以为非常左值、常左值或右值
  • 表达式的结果为右值
// 运算类双目操作符函数
#include <iostream>
using namespace std;class Human{
public:Human(int age = 0, const char* name="匿名"):m_age(age),m_name(name){// [int m_age = age;]// [string m_name(name);]}void getInfo(){cout << "姓名:" << m_name << ", 年龄:" << m_age << endl;}// 成员形式操作符函数
//  Human operator+(const Human& r) const {
//      return Human(this->m_age+r.m_age, (this->m_name+"+"+r.m_name).c_str());
//  }
private:int m_age;string m_name;friend Human operator+(const Human& l,const Human& r); // 友元声明
};
// 全局形式操作符函数
Human operator+(const Human& l, const Human& r){return Human(l.m_age+r.m_age, (l.m_name+"+"+r.m_name).c_str());
}int main(void){Human a(22,"张飞"), b(20,"赵云");  // 非常左值const Human c(25,"关羽"), d(32,"马超"); // 常左值Human res = a + b; // ==> a.operator+(b)  或 operator+(a,b)res.getInfo();res = c + d; // ==> c.operator+(d)  或 operator+(c,d)res.getInfo();res = Human(45,"黄忠") + Human(35,"刘备"); // ==> Human(45,"黄忠").operator+(Human(35,"刘备")) 或 //     operator+(Human(45,"黄忠"),Human(35,"刘备"))res.getInfo();return 0;
}

赋值类双目操作符:=、+=、-=、*=、/=等

  • 右操作数可以为非常左值、常左值或右值,但左操作数必须为非常左值
  • 表达式结果为左操作数本身(而非副本)
// 赋值类双目操作符函数
#include <iostream>
using namespace std;class Human{
public:Human(int age = 0, const char* name="匿名"):m_age(age),m_name(name){// [int m_age = age;]// [string m_name(name);]}void getInfo(){cout << "姓名:" << m_name << ", 年龄:" << m_age << endl;}// 成员形式操作符函数Human& operator+=(const Human& r){this->m_age = this->m_age + r.m_age;this->m_name = this->m_name + "+" + r.m_name;return *this;}
private:int m_age;string m_name;friend Human operator+(const Human& l,const Human& r); // 友元声明
};全局形式操作符函数
//Human& operator+(Human& l, const Human& r){
//       l->m_age = l->m_age + r.m_age;
//       l->m_name = l->m_name + "+" + r.m_name;
//       return *l;
//}int main(void){Human a(22,"张飞"), b(20,"赵云");  // 非常左值const Human c(25,"关羽"), d(32,"马超"); // 常左值((a+=b)+=c)+=Human(45,"黄忠");a.getInfo();return 0;
}

比较类双目操作符:>、<、==、<=、>=等

  • 左右操作数为非常左值、常左值或右值
  • 表达式结果为 bool
// 比较类双目操作符函数
#include <iostream>
using namespace std;class Human{
public:Human(int age = 0, const char* name="匿名"):m_age(age),m_name(name){// [int m_age = age;]// [string m_name(name);]}void getInfo(){cout << "姓名:" << m_name << ", 年龄:" << m_age << endl;}
//    // 成员形式操作符函数
//    bool operator==(/*const Human* this */ const Human& that)const{
//        return this->m_age==that.m_age && this->m_name==that.m_name;
//    }
//    bool operator!=(/*const Human* this */ const Human& that)const{return this->m_age!=that.m_age || this->m_name!=that.m_name;
//        return !(*this==that);//使用operator==
//    }
private:int m_age;string m_name;friend bool operator==(const Human& l, const Human& r); // 友元声明friend bool operator!=(const Human& l, const Human& r); // 友元声明
};
// 全局形式操作符函数
bool operator==(const Human& l, const Human& r){return l.m_age==r.m_age && l.m_name==r.m_name;
}
bool operator!=(const Human& l, const Human& r){
//      return l.m_age!=r.m_age || l.m_name!=r.m_name;return !(l==r);//使用operator==
}int main(void){Human a(22,"张飞"), b(20,"赵云");  // 非常左值const Human c(25,"关羽"), d(32,"马超"); // 常左值cout << (a == b) << endl; //0 ==> a.operator==(b) 或者 ...cout << (a != b) << endl; //1 ==> a.operator!=(b) 或者 ...cout << (c == d) << endl; //0 ==> c.operator==(d) 或者 ...cout << (c != d) << endl; //1 ==> c.operator!=(d) 或者 ...cout << (Human(45,"黄忠") == Human(35,"刘备")) << endl; //0 ==> Human(45,"黄忠").operator==(Human(35,"刘备")) 或者 ...cout << (Human(45,"黄忠") != Human(35,"刘备")) << endl; //1 ==> Human(45,"黄忠").operator!=(Human(35,"刘备")) 或者 ...return 0;
}

经典单目操作符

运算类单目操作符:-、~、!等

  • 操作数为非常左值、常左值或右值
  • 表达式的结果为右值
// 运算类单目操作符函数
#include <iostream>
using namespace std;class Human{
public:Human(int age = 0, const char* name="匿名"):m_age(age),m_name(name){// [int m_age = age;]// [string m_name(name);]}void getInfo(){cout << "姓名:" << m_name << ", 年龄:" << m_age << endl;}// 成员形式操作符函数Human operator-(/* const Human* this */)const{return Human(-this->m_age,("-"+this->m_name).c_str());}
private:int m_age;string m_name;
//    friend Human operator-(const Human& l); // 友元声明
};//Human operator-(const Human& l){
//    return Human(-l.m_age,("-"+l.m_name).c_str());
//}
int main(void){Human a(22,"张飞"), b(20,"赵云");  // 非常左值const Human c(25,"关羽"), d(32,"马超"); // 常左值Human res = -a; // ==> a.operator-() 或  ...res.getInfo();//姓名:-张飞, 年龄:-22res = -c; // ==> c.operator-() 或  ...res.getInfo();//姓名:-关羽, 年龄:-25res = -Human(45,"黄忠"); // ==> Human(45,"黄忠").operator-() 或 ...res.getInfo();//姓名:-黄忠, 年龄:-45return 0;
}

前自增减类单目操作符: 前++、前–

  • 操作数为非常左值
  • 表达式的结果为操作数本身(而非副本)

后自增减类单目操作符: 后+ +、后–

  • 操作数为非常左值
  • 表达式的结果为右值,且为自增减以前的值
// 自增减类单目操作符函数
#include <iostream>
using namespace std;class Human{
public:Human(int age = 0, const char* name="匿名"):m_age(age),m_name(name){// [int m_age = age;]// [string m_name(name);]}void getInfo(){cout << "姓名:" << m_name << ", 年龄:" << m_age << endl;}//成员形式操作符函数
//    //   前++   ++a
//    Human& operator++(/* Human* this */){
//        this->m_age+=1;   // 直接加1
//        this->m_name+="a";   // 直接加
//        return *this;
//    }后++  a++
//    Human operator++(/* Human* this */int){
//        Human old = *this;   // 备份原来的值
//        this->m_age+=1;  // 直接加1
//        this->m_name+="a";   // 直接加
//        return old;  // 返回原来的值
//    }
private:int m_age;string m_name;friend  Human& operator++(Human&  l); // 友元声明friend  Human operator++(Human&  l,int); // 友元声明
};//   前++   ++aHuman& operator++(Human&  l){l.m_age+=1;   // 直接加1l.m_name+="a";   // 直接加return l;}//    后++  a++Human operator++(Human& l,int){Human old = l;   // 备份原来的值l.m_age+=1;  // 直接加1l.m_name+="a";   // 直接加return old;  // 返回原来的值}int main(void){Human a(22,"张飞"), b(20,"赵云");  // 非常左值const Human c(25,"关羽"), d(32,"马超"); // 常左值//姓名:张飞a, 年龄:23(++a).getInfo(); // a.operator++() 或 ...//姓名:赵云, 年龄:20(/*|...|*/b++).getInfo(); // b.operator++(0) 或 ...//姓名:赵云a, 年龄:21b.getInfo();return 0;
}

其他操作符

输出操作符: <<

  • 左操作数为非常左值形式的输出流(ostream)对象,右操作数为左值或右值
  • 表达式的结果为左操作数本身(而非副本)
  • 左操作数的类型为ostream,若以成员函数形式重载该操作符,就应将其定义为ostream类的成员,该类为标准库提供,无法添加新的成员,因此只能以全局函数形式重载该操作符

ostream& operator< < (ostream& os, const RIGHT& right) { ...}

// 输入/输出流操作符函数
#include <iostream>
using namespace std;class Human{
public:Human(int age = 0, const char* name="匿名"):m_age(age),m_name(name){// [int m_age = age;]// [string m_name(name);]}
/*  void getInfo(){cout << "姓名:" << m_name << ", 年龄:" << m_age << endl;}*/// 成员形式操作符函数
private:int m_age;string m_name;friend ostream& operator<<(ostream& os, const Human& that);friend istream& operator>>(istream& is, Human& that);
};
// 全局形式操作符函数
ostream& operator<<(ostream& os, const Human& that){os << "姓名:" << that.m_name << ", 年龄:" << that.m_age;return os;
}//istream& operator>>(istream& is, Human& that){
//    is >> that.m_name >> that.m_age;
//    return is;
//}int main(void){Human a(22,"张飞");  // 非常左值const Human b(20,"赵云");  // 常左值cout << a << endl; // cout.operator<<(a) 或 operator<<(cout,a)cout << b << endl; // cout.operator<<(b) 或 operator<<(cout,b)cout << Human(45,"黄忠") << endl; // cout.operator<<(Human(45,"黄忠")) 或 operator<<(cout,Human(45,"黄忠"))//    cin >> a; // cin.operator>>(a) 或 operator>>(cin,a)cout << a << endl;return 0;
}

输入操作符: >>

  • 左操作数为非常左值形式的输入流(istream)对象,右操作数为非常左值
  • 表达式的结果为左操作数本身(而非副本)
  • 左操作数的类型为istream,若以成员函数形式重载该操作符,就应将其定义为istream类的成员,该类为标准库提供,无法添加新的成员,因此只能以全局函数形式重载该操作符

istream& operator>> (istream& is, RIGHT& right) { ...}

// 输入/输出流操作符函数
#include <iostream>
using namespace std;class Human{
public:Human(int age = 0, const char* name="匿名"):m_age(age),m_name(name){// [int m_age = age;]// [string m_name(name);]}
/*  void getInfo(){cout << "姓名:" << m_name << ", 年龄:" << m_age << endl;}*/// 成员形式操作符函数
private:int m_age;string m_name;friend ostream& operator<<(ostream& os, const Human& that);friend istream& operator>>(istream& is, Human& that);
};
// 全局形式操作符函数
ostream& operator<<(ostream& os, const Human& that){os << "姓名:" << that.m_name << ", 年龄:" << that.m_age;return os;
}istream& operator>>(istream& is, Human& that){is >> that.m_name >> that.m_age;return is;
}int main(void){Human a(22,"张飞");  // 非常左值cin >> a; // cin.operator>>(a) 或 operator>>(cin,a)cout << a << endl;return 0;
}

下标操作符:[]

  • 一般用于在容器类型中以下标方式获取数据元素
  • 非常容器的元素为非常左值,常容器的元素为常左值

类型转换操作符

若源类型是基本类型,目标类型是类类型,则只能通过类型转换构造函数实现自定义类型转换

class 目标类型{目标类型(const 源类型& src){ ... }
}

若源类型是类类型,目标类型是基本类型,则只能通过类型转换操作符函数 实现自定义类型转换

class 源类型{operator 目标类型(void) const { ...}
}

若源类型和目标类型都是类类型 (而非基本类型) ,则既可以通过类型转换构造函数也可以通过类型转换操作符函数实现自定义类型转换,但不要两者同时使用

若源类型和目标类型都是基本类型,则无法实现自定义类型转换,基本类型间的类型转换规则完全由编译器内置

操作符重载的局限

不是所有的操作符都能重载,以下操作符不能重载

  • 作用域限定操作符(::)
  • 直接成员访问操作符(.)
  • 条件操作符(?:)
  • 字节长度操作符(sizeof)
  • 类型信息操作符(typeid)

无法重载所有操作数均为基本类型的操作符: 如实现 1+1=3

c++的前++和后++

  1. 在C语言中
    前++: 先加1,再使用 ++a
    后++: 先使用,再加1 a++
  2. 在C++语言中,不管是前++还是后++,都是直接加1(内部原理和C语言并不同)
    但是C++希望用户感觉和C一样

c++的前++和后++的区别

  • 表达式方式区别:i++是先取变量i,再将变量i值+1;而++i是先将变量i值+1,再取变量i。在循环遍历容器变量时,这两种方式的结果都是一样的,但是,本质的效率上有很大的区别,下面介绍另一种效率区别。
  • 效率:两种方式iterator遍历的次数是相同的,但在STL中效率不同,前++返回引用,后++返回一个临时对象,因为iterator是类模板,使用 it++这种形式要返回一个无用的临时对象,而it++是函数重载,所以编译器无法对其进行优化,所以每遍历一个元素,你就创建并销毁了一个无用的临时对象。C++的标准库,还有符合标准C++的教材,除了特殊需要和对内置类型外,基本都是使用++it来进行元素遍历的,不管是源代码还是教材中都是如此。

下面是标准库源码:
在这里插入图片描述

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

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

相关文章

elment-table设置el-table-column的label里面的文字换行居中显示

效果图如下&#xff1a; 直接上代码&#xff1a; <el-table class"ut-mt-2" row-key"company" default-expand-all:data"stateQuery.data" style"width: 100%":tree-props"{ children: departList, hasChildren: hasChildre…

Si24R03—低功耗 SOC 芯片(集成RISC-V内核+2.4GHz无线收发器)

Si24R03是一款高度集成的低功耗SOC芯片&#xff0c;其集成了基于RISC-V核的低功耗MCU和工作在2.4GHz ISM频段的无线收发器模块。 MCU模块具有低功耗、Low Pin Count、宽电压工作范围&#xff0c;集成了13/14/15/16位精度的ADC、LVD、UART、SPI、I2C、TIMER、WUP、IWDG、RTC等丰…

PandoraFMS 监控软件 任意文件上传漏洞复现

0x01 产品简介 Pandora FMS 是用于监控计算机网络的软件。 Pandora FMS 允许以可视化方式监控来自不同操作系统、服务器、应用程序和硬件系统(例如防火墙、代理、数据库、Web 服务器或路由器)的多个参数的状态和性能。 0x02 漏洞概述 PandoraFMS upload_head_image.php 接…

NLP项目实战01之电影评论分类

介绍&#xff1a; 欢迎来到本篇文章&#xff01;在这里&#xff0c;我们将探讨一个常见而重要的自然语言处理任务——文本分类。具体而言&#xff0c;我们将关注情感分析任务&#xff0c;即通过分析电影评论的情感来判断评论是正面的、负面的。 展示&#xff1a; 训练展示如下…

【基于LicheePi-4A的 人脸识别系统软件设计】

参考:https://www.xrvm.cn/community/post/detail?spm=a2cl5.27438731.0.0.31d40dck0dckmg&id=4253195599836418048 1.前言 原先计划做基于深度学习的炸药抓取和智能填装方法研究,但是后来发现板卡不支持pyrealsense2等多个依赖包。因此改变策略,做一款基于LicheePi…

【Python】列表乘积的计算时间

概述 使用以下三种模式测量了计算列表乘积所需的时间。 使用 for 语句传递list使用math模块使用numpy 下面是实际运行的代码。 import timestart time.time() A [1] * 100000000 ans 1 for a in A:ans * a print("list loop:", time.time() - start)import m…

有哪些已经上线的vue商城项目?

前言 下面是一些商城的项目&#xff0c;需要练手的同学可以挑选一些来练&#xff0c;废话少说&#xff0c;让我们直接开始正题~~ 1、newbee-mall-vue3-app 是一个基于 Vue 3 和 TypeScript 的电商前端项目&#xff0c;它是 newbee-mall 项目的升级版。该项目包含了商品列表、…

内网环境下 - 安装linux命令、搭建docker以及安装镜像

一 内网环境安装docker 先在外网环境下载好docker二进制文件docker二进制文件下载&#xff0c;要下载对应硬件平台的文件&#xff0c;否则不兼容 如下载linux平台下的文件&#xff0c;直接访问这里即可linux版本docker二进制文件 这里下载docker-24.0.5.tgz 将下载好的文件…

计算机存储单位 + 程序编译过程

C语言的编译过程 计算机存储单位 头文件包含的两种方式 使用 C/C 程序常用的IDE 常用的C语言编译器&#xff1a; 在选择编译器时&#xff0c;需考虑平台兼容性、性能优化、调试工具和开发人员的个人偏好等因素。 详细教程可转 爱编程的大丙

Java编程中通用的正则表达式(一)

正则表达式&#xff08;Regular Expression&#xff0c;简称RegEx&#xff09;&#xff0c;又称常规表示法、正则表示、正规表示式、规则表达式、常式、表达式等&#xff0c;是计算机科学中的一个概念。正则表达式是用于描述某种特定模式的字符序列&#xff0c;特别是用来匹配、…

持续集成和持续交付

引言 CI/CD 是一种通过在应用开发阶段引入自动化来频繁向客户交付应用的方法。CI/CD 的核心概念是持续集成、持续交付和持续部署。作为一种面向开发和运维团队的解决方案&#xff0c;CI/CD 主要针对在集成新代码时所引发的问题&#xff08;亦称&#xff1a;“集成地狱”&#…

idea__SpringBoot微服务05——JSR303校验(新注解)(新的依赖),配置文件优先级,多环境切换

JSR303校验&#xff0c;配置文件优先级&#xff0c;多环境切换 一、JSR303数据校验二、配置文件优先级三、多环境切换一、properties多环境切换二、yaml多环境切换————————创作不易&#xff0c;如觉不错&#xff0c;随手点赞&#xff0c;关注&#xff0c;收藏(*&#x…

电脑待机怎么设置?让你的电脑更加节能

在日常使用电脑的过程中&#xff0c;合理设置待机模式是一项省电且环保的好习惯。然而&#xff0c;许多用户对于如何设置电脑待机感到困扰。那么电脑待机怎么设置呢&#xff1f;本文将深入探讨三种常用的电脑待机设置方法&#xff0c;通过详细的步骤&#xff0c;帮助用户更好地…

【数据结构】顺序表的定义和运算

目录 1.初始化 2.插入 3.删除 4.查找 5.修改 6.长度 7.遍历 8.完整代码 &#x1f308;嗨&#xff01;我是Filotimo__&#x1f308;。很高兴与大家相识&#xff0c;希望我的博客能对你有所帮助。 &#x1f4a1;本文由Filotimo__✍️原创&#xff0c;首发于CSDN&#x1f4da;。 &…

web前端开发html/css练习

目标图&#xff1a; 素材&#xff1a; 代码&#xff1a; <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns"http://www.w3.org/1999/xhtml"…

使用RSA工具进行对信息加解密

我们在开发中需要对用户敏感数据进行加解密&#xff0c;比如密码 这边科普一下RSA算法 RSA是非对称加密算法&#xff0c;与对称加密算法不同;在对称加密中&#xff0c;相同的密钥用于加密和解密数据,因此密钥的安全性至关重要;而在RSA非对称加密中&#xff0c;有两个密钥&…

【USRP】5G / 6G OAI 系统 5g / 6G OAI system

面向5G/6G科研应用 USRP专门用于5G/6G产品的原型开发与验证。该系统可以在实验室搭建一个真实的5G 网络&#xff0c;基于开源的代码&#xff0c;专为科研用户设计。 软件无线电架构&#xff0c;构建真实5G移动通信系统 X410 采用了目前流行的异构式系统&#xff0c;融合了FP…

使用 OMSA 和 OME 工具管理多个服务器

文章目录 Dell Remote Access Controller (iDRAC)OpenManage Server Administrator&#xff08;OMSA&#xff09;OpenManage EnterpriseSupportAssist Enterprise推荐阅读 在DELL服务器的管理工具中&#xff0c;有多个管理工具&#xff0c;今天我们将分享这几个工具的关联性以及…

【Git系列】branch和tag

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

将单体应用程序迁移到微服务

多年来&#xff0c;我处理过多个单体应用&#xff0c;并将其中一些迁移到了微服务架构。我打算写下我所学到的东西以及我从经验中用到的策略&#xff0c;以实现成功的迁移。在这篇文章中&#xff0c;我将以AWS为例&#xff0c;但基本原则保持不变&#xff0c;可用于任何类型的基…