8、操作符重载

news2024/11/26 16:22:45

友元

  • 可以通过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();//姓名:-张飞, 年龄:-22

    res = -c; // ==> c.operator-() 或  ...
    res.getInfo();//姓名:-关羽, 年龄:-25

    res = -Human(45,"黄忠"); // ==> Human(45,"黄忠").operator-() 或 ...
    res.getInfo();//姓名:-黄忠, 年龄:-45

    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;
    }
    //成员形式操作符函数
//    //   前++   ++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); // 友元声明
};
    //   前++   ++a
    Human& operator++(Human&  l){
        l.m_age+=1;   // 直接加1
        l.m_name+="a";   // 直接加
        return l;
    }
    //    后++  a++
    Human operator++(Human& l,int){
        Human old = l;   // 备份原来的值
        l.m_age+=1;  // 直接加1
        l.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, 年龄:21
    b.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.coloradmin.cn/o/1296403.html

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

相关文章

Nginx按指定格式记录访问日志

今天突然想起来一个日志的一个东西,因为拉项目无意中看到了日志文件的一些东西,现在不经常做后端了,加上其他的一些原因吧.有时候有些问题也没想太多,马马虎虎就过了,后来想想还是要记录一下这方面的处理过程吧: 一般我们作为开发人员关注的日志只是在应用程序层面的,我们称它…

Hanlp自然语言处理如何再Spring Boot中使用

一、HanLP HanLP (Hankcs NLP) 是一个自然语言处理工具包&#xff0c;具有功能强大、性能高效、易于使用的特点。HanLP 主要支持中文文本处理&#xff0c;包括分词、词性标注、命名实体识别、依存句法分析、关键词提取、文本分类、情感分析等多种功能。 HanLP 可以在 Java、Py…

delphi/python 实现小红书xhs用户作品列表和图片/视频无水印解析

技术学习&#xff0c;请勿用与非法用途&#xff01;&#xff01;&#xff01; 成品图用户作品列表接口 /api/sns/web/v1/user_posted?num30&cursor&user_id642bf0850000000011022c4e&image_scenes http Get方式&#xff0c;请求头需要带上x-s x-t签名验证笔记明细…

二叉树的层序遍历[中等]

优质博文&#xff1a;IT-BLOG-CN 一、题目 给你二叉树的根节点root&#xff0c;返回其节点值的 层序遍历 。&#xff08;即逐层地&#xff0c;从左到右访问所有节点&#xff09;。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;[[3],…

【算法每日一练]-图论(保姆级教程篇12 tarjan篇)#POJ3352道路建设 #POJ2553图的底部 #POJ1236校园网络 #缩点

目录&#xff1a; 今天知识点 加边使得无向图图变成双连通图 找出度为0的强连通分量 加边使得有向图变成强连通图 将有向图转成DAG图进行dp POJ3352&#xff1a;道路建设 思路&#xff1a; POJ2553&#xff1a;图的底部 思路&#xff1a; POJ1236校园网络 思路&#x…

[ndss 2023]确保联邦敏感主题分类免受中毒攻击

Securing Federated Sensitive Topic Classification against Poisoning Attacks 摘要 我们提出了一种基于联邦学习 (FL) 的解决方案&#xff0c;用于构建能够检测包含敏感内容的 URL 的分布式分类器&#xff0c;即与健康、政治信仰、性取向等类别相关的内容。尽管这样的分类器…

docker:搭建私有仓库

文章目录 1、拉取镜像2、运行容器3、测试成功4、修改daemon.json5、重启docker 服务6、上传镜像到私有仓库6.1 标记某个镜像为私有仓库镜像6.2 上传镜像到私有仓库 其他注意项 1、拉取镜像 docker pull registry2、运行容器 docker run -di --nameregistry -p 5000:5000 regi…

3DCAT+上汽奥迪:打造新零售汽车配置器实时云渲染解决方案

在 5G、云计算等技术飞速发展的加持下&#xff0c;云渲染技术迎来了突飞猛进的发展。在这样的背景下&#xff0c;3DCAT应运而生&#xff0c;成为了业内知名的实时云渲染服务商之一。 交互式3D实时云看车作为云渲染技术的一种使用场景&#xff0c;也逐步成为一种新的看车方式&a…

HttpComponents: 领域对象的设计

1. HTTP协议 1.1 HTTP请求 HTTP请求由请求头、请求体两部分组成&#xff0c;请求头又分为请求行(request line)和普通的请求头组成。通过浏览器的开发者工具&#xff0c;我们能查看请求和响应的详情。 下面是一个HTTP请求发送的完整内容。 POST https://track.abc.com/v4/tr…

金融银行业更适合申请哪种SSL证书?

在当今数字化时代&#xff0c;金融行业的重要性日益增加。越来越多的金融交易和敏感信息在线进行&#xff0c;金融银行机构必须采取必要的措施来保护客户数据的安全。SSL证书作为一种重要的安全技术工具&#xff0c;可以帮助金融银行机构加密数据传输&#xff0c;验证网站身份&…

html中一个div中平均一行分配四个盒子,可展开与收起所有的盒子

html中一个div中平均一行分配四个盒子&#xff0c;可展开与收起所有的盒子 1.截图显示部分 2.代码展示部分 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"wid…

物易管预测性维护平台3.6.0版本上线,工况数据处理、设备故障模型、数据可视化等方面带来全新功能体验

物易管设备预测性维护平台V3.6.0版本近日正式发布上线&#xff0c;相较V3.5.0版本次主要新增优化设备工况数据接入、工况数据模型训练、数据可视化以及设备监测详情优化四个板块。新版本在处理工况数据、设备故障模型、数据分析展示以及设备监测方面带来全新的体验。 01设备工况…

【投稿】期刊选择

一、期刊影响力评价方法 只要投稿的期刊&#xff0c;被上述三个索引收录&#xff0c;那就说明该期刊的影响力是得到认可的。 二、如何选择合适的期刊 研究工作和目标期刊进行权衡。

[GXYCTF2019]禁止套娃1

提示 git泄露无参数rce &#xff01;&#xff01;注意需要python3环境 github里dirsearch工具下载位置 ###可能需要开节点才能打开 百度网盘dirsearch下载地址 ###如果github里下载不了可以在网盘下载 提取码sx5d 只给了flag在哪里呢&#xff0c;那么应该就是要让…

电子学会C/C++编程等级考试2021年09月(五级)真题解析

C/C++等级考试(1~8级)全部真题・点这里 第1题:抓牛 农夫知道一头牛的位置,想要抓住它。农夫和牛都位于数轴上,农夫起始位于点N(0<=N<=100000),牛位于点K(0<=K<=100000)。农夫有两种移动方式: 1、从X移动到X-1或X+1,每次移动花费一分钟 2、从X移动到2*X,每…

Axios 拦截器实战教程:简单易懂

Axios 提供了一种称为 “拦截器&#xff08;interceptors&#xff09;” 的功能&#xff0c;使我们能够在请求或响应被发送或处理之前对它们进行全局处理。拦截器为我们提供了一种简洁而强大的方式来转换请求和响应、进行错误处理、添加认证信息等操作。在本文中&#xff0c;我…

案例063:基于微信小程序的传染病防控宣传系统

文末获取源码 开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 数据库&#xff1a;mysql 5.7 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a;Maven3.5.4 小程序框架&#xff1a;uniapp 小程序开发软件&#xff1a;HBuilder …

如何进行更好的面试回复之缓存函数在项目中的性能优化?

缓存函数是一种提高函数性能的技术&#xff0c;在函数被调用时&#xff0c;会将计算结果缓存起来&#xff0c;以便在后续的调用中直接返回缓存的结果&#xff0c;从而减少了重复计算的时间。 缓存函数的实现通常包括两个步骤&#xff1a; 判断缓存是否存在&#xff1a;在函数被…

Mysql 命令行导出SQL文件和导入文件

1-导出SQL文件 要导出 MySQL 数据库到一个 SQL 文件&#xff0c;你可以使用 mysqldump 工具&#xff0c;它是 MySQL 的一个命令行工具&#xff0c;以下是一些步骤&#xff1a; 打开终端&#xff0c;并使用以下命令来执行导出操作&#xff1a; mysqldump -u wqzbxh -h 1.137.15…

DAP数据集成与算法模型如何结合使用

企业信息化建设会越来越完善&#xff0c;越来越体系化&#xff0c;当今数据时代背景下更加强调、重视数据的价值&#xff0c;以数据说话&#xff0c;通过数据为企业提升渠道转化率、改善企业产品、实现精准运营&#xff0c;为企业打造自助模式的数据分析成果&#xff0c;以数据…