学习记录——day41 运算符重载

2024-09-03 16:20

本文主要是介绍学习记录——day41 运算符重载,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

        运算符默认不支持自定义的类,但是可以通过运算符重载扩展运算符的属于范围

        运算符重载,也是实现泛型编程的一种,能够实现“一符多用”,可以使用运算符重载来完成对象与对象之间的符号运算

        注:运算符重载仅针对类对象 不影响基础数据类型

一、运算符重载函数

1)函数名:统一为 operator# //这里的#表示要被重载的运算符

2)参数:根据运算符的功能和位置而定,

         如:全局函数版双目运算符参数有两个,成员函数版双目运算符参数一个

                全局函数版,单目运算符参数有一个,成员函数版单目运算符参数无

3> 返回值:根据实际情况而定

二、调用原则和调用机制

        调用时机:当对象使用该运算符时,系统自动调用运算符重载函数

        调用机制:左调右参原则,运算符左侧是函数的调用者,运算符右侧是函数的参数

                                例如:a = b;       //a.operator=(b);

                                           s1 + s2;   //s1.operator+(s2);

下列以此类为例:

class Complax
{
private:
        int real;            //实部    
        int vir;             //虚部
public:
         ......
};

三、算数运算符重载

1)种类:+、-、*、/、%

2)算术运算符属于双目运算符,格式:L # R; L表示左操作数,#表示运算符号,R表示右操作数

3)左操作(L):既可以是左值也可以是右值

     右操作数(R):既可以是左值也可以是右值

     运算结果:只能是右值

4)格式:

成员函数版:const 类名 operator#(const 类名 &R) const

           解析:第一个const保护运算结果不被修改

                      第二个const保护右操作数在运算过程中不被修改

                      第三个const保护左操作数自身在运算过程中不被修改

全局函数版:const 类名 operator#(const 类名 &L,const 类名 &R)

以 + 为例      (参数、返回值、函数体内部逻辑根据实际情况改变)

成员函数版

class Complax
{
private:int real;            //实部    int vir;             //虚部
public://成员函数版const Complax operator+(const Complax &R)const{Complax temp;       //无参构造temp.real = this->real + R.real;temp.vir = this->vir + R.vir;return temp;}
};    

 全局函数版

//全局函数版class Complax
{
private:int real;            //实部    int vir;             //虚部
public://实现全局函数版,需要将全局函数版设置成友元函数friend const Complax operator+(const Complax &L, const Complax &R);
};const Complax operator-(const Complax &L, const Complax &R)
{Complax temp;       //无参构造temp.real = L.real - R.real;temp.vir = R.vir - R.vir;return temp;
}

四、赋值类运算符重载

1)种类:=、+=、-=、*=、/=、%=

2)赋值运算符属于双目运算符,格式:L # R; L表示左操作数,#表示运算符号,R表示右操作数

3)左操作(L):只能是左值

     右操作数(R):既可以是左值也可以是右值

     运算结果:左操作数自身的引用

4)格式:

        成员函数版:类名 & operator#(const 类名 &R)

        全局函数版:类名 & operator#( 类名 &L,const 类名 &R)

五、关系运算符重载函数

1)种类:>、=、

2)关系运算符属于双目运算符,格式:L # R; L表示左操作数,#表示运算符号,R表示右操作数

3)左操作(L):既可以是左值也可以是右值

     右操作数(R):既可以是左值也可以是右值

     运算结果:bool类型的右值

4)格式:

        成员函数版:const bool operator#(const 类名 &R) const

        全局函数版:const bool operator#(const 类名 &L,const 类名 &R)

六、单目运算符

1)种类:-(负号) 、!

2)格式:# R; #表示运算符号,R表示右操作数

3)操作数(R):既可以是左值也可以是右值

     运算结果:同类的一个右值

4)格式:

        成员函数版:const 类名 operator#() const

        全局函数版:const bool operator#(const 类名 &R)

七、自增自减运算

1)种类:++ 、 --

2)格式:# R; #表示运算符号,R表示右操作数

3)操作数(R):只能是左值

      运算结果:  

              前置:是自身的引用

                         成员格式:类名 &operator#()

                         全局格式:类名 &operator#(类名 &R)              

           

              后置:临时值

                         成员格式:类名 operator#(int)

                         全局格式:类名 operator#(类名 &R, int)

八、插入和提取运算符重载

1)插入和提取运算符的来源

namespace std
{
    ostream cout;
    istream cin;
}

2)由于运算符重载函数的调用遵循左调有参原则,所以,自定义类的重载函数,需要流对象和自定义类的对象

        例如:cout

3)此时,原则上来说,需要在流所在的类对象中,写成员函数,难度较大,所以,对于该类的重载函数,我们只能实现全局函数版,将该函数作为类的友元函数

4)由于不需要使用istream和ostream类中的私有成员,所以,全局函数版的重载函数不需要在流对应的类中,声明友元函数

        如果,重载函数中,需要使用自定义的类中的私有成员,则需要在自定义类中,声明该全局函数为友元函数

5)格式:

        ostream& operator

        istream& operator>>(istream &L, 类名 &R)

九、类型转换运算符

1)有时,需要将类对象进行强制类型转换为其他数据类型,此时就需要在类体内提供类型转换运算符重载函数

2)定义格式: operator 要转换的类型() { 返回对应类型的数据 }

十、函数对象(仿函数)

1)本质上就是重载 () 运算符,由于调用时,跟函数调用一样,所以称为仿函数

2)定义格式: operator() (参数列表) {函数体内容}

3)调用格式:对象名(实参名); //对象 . operator() (实参名)

十一、运算符重载的限制

1>不能重载运算符 ::(作用域解析)、.(成员访问)、.*(通过成员指针的成员访问)及 ?:(三元条件)。

2>不能创建新运算符,例如 **、<> 或 &|。

3>运算符 && 与 || 的重载失去短路求值。

4>重载的运算符 -> 必须要么返回裸指针,要么(按引用或值)返回同样重载了运算符 -> 的对象。

5>不可能更改运算符的优先级、结合方向或操作数的数量。

6>&&、|| 和 ,(逗号)在被重载时失去其特殊的定序性质,并且即使不使用函数调用记法,也表现为与常规的函数调用相似。
(C++17 前)

示例

#include <iostream>using namespace std;//定义一个复数类: 由实部和虚部组成的一个数据  a + bi
class Complax
{
private:int real;            //实部int vir;             //虚部public:Complax() {cout<<"无参构造"<<endl;}            //无参构造Complax(int r, int v):real(r),vir(v) {cout<<"有参构造"<<endl;}   //有参构造~Complax() {cout<<"析构函数"<<endl;}           //析构函数//定义输出函数void show(){if(vir > 0){cout<<real << "+"<<vir<<"i"<<endl;}else{cout<<real << vir<<"i"<<endl;}}//定义成员函数版完成两个复数相加:实部+实部   虚部+虚部const Complax operator+(const Complax &R)const{Complax temp;       //无参构造temp.real = this->real + R.real;temp.vir = this->vir + R.vir;return temp;}//实现全局函数版,需要将全局函数版设置成友元函数friend const Complax operator-(const Complax &L, const Complax &R);//成员函数版完成加等于运算符重载: 实部 += 实部   虚部+=虚部Complax &operator+=(const Complax &R){this->real += R.real;this->vir += R.vir;return *this;}//定义成员函数版完成关系运算符重载: 实部>实部   && 虚部>虚部bool operator>(const Complax &R)const{return this->real>R.real && this->vir>R.vir;}//定义成员函数版完成负号运算符重载:   实部 = -实部    虚部=-虚部const Complax operator-()const{Complax temp;temp.real = -this->real;temp.vir = -this->vir;return temp;}//定义成员函数版完成++前置运算: 实部 +=1   虚部+=1Complax &operator++(){this->real++;this->vir++;return *this;}//定义成员函数版完成++后置运算: 实部 +=1   虚部+=1Complax operator++(int)        //这里括号中的int仅仅起到占位作用,使用的是哑元{Complax temp;temp.real = this->real++;temp.vir = this->vir++;return temp;}//将插入运算符重载函数,设置成友元函数friend ostream & operator<<(ostream &L, const Complax &R);//定义类型转换运算符重载函数operator int(){return this->real + this->vir;}//重载小括号运算符,完成仿函数void operator()(string msg){cout << msg<< endl;}};//定义全局函数版完成两个复数相减
const Complax operator-(const Complax &L, const Complax &R)
{Complax temp;       //无参构造temp.real = L.real - R.real;temp.vir = R.vir - R.vir;return temp;
}//自定义插入运算符重载函数:只能实现全局函数版
ostream & operator<<(ostream &L, const Complax &R)
{//输出内容if(R.vir > 0){L<<R.real << "+"<<R.vir<<"i"<<endl;}else{L<<R.real << R.vir<<"i"<<endl;}//返回左操作数自身return L;
}int main()
{Complax c1(5,7);           //有参构造c1.show();                //5+7iComplax c2(3, -2);            //有参构造c2.show();                    //3-2icout<<"**************************************"<<endl;Complax c3 = c1+c2;       //调用加号 运算符重载函数c3.show();                //8+5icout<<"**************************************"<<endl;(c1+=c2) += c3;          //调用加等于运算符重载函数c1.show();            //16+10ic2.show();             //3-2ic3.show();              //8+5icout<<"**************************************"<<endl;if(c1>c2)                      //调用关系运算符重载函数{cout<<"yes"<<endl;}else{cout<<"no"<<endl;}cout<<"**************************************"<<endl;Complax c4 = -c1;          //调用负号运算符重载c4.show();                  // -16 - 10icout<<"**************************************"<<endl;/*int num = 5;num++++;          //后置自增后,返回结果是一个右值++++num;          //前置自增后,返回的结果是一个左值*/Complax c5 = ++++c1;            //前置自增,先加再用c5.show();         //18+12ic1.show();         //18+12icout<<"**************************************"<<endl;Complax c6 = c1++;        //后置自增,先用再加c6.show();             //18+12ic1.show();             //19+13icout<<"**************************************"<<endl;cout<<c1 <<c2;          //cout.operator<<(c1);cout<<"**************************************"<<endl;int num = (int)c1;         //调用强制类型转换函数cout<<"num = "<<num<<endl;      //32cout<<"**************************************"<<endl;//仿函数的调用c1("hello world");cout<<"**************************************"<<endl;return 0;
}

这篇关于学习记录——day41 运算符重载的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1133433

相关文章

Python MySQL如何通过Binlog获取变更记录恢复数据

《PythonMySQL如何通过Binlog获取变更记录恢复数据》本文介绍了如何使用Python和pymysqlreplication库通过MySQL的二进制日志(Binlog)获取数据库的变更记录... 目录python mysql通过Binlog获取变更记录恢复数据1.安装pymysqlreplicat

Servlet中配置和使用过滤器的步骤记录

《Servlet中配置和使用过滤器的步骤记录》:本文主要介绍在Servlet中配置和使用过滤器的方法,包括创建过滤器类、配置过滤器以及在Web应用中使用过滤器等步骤,文中通过代码介绍的非常详细,需... 目录创建过滤器类配置过滤器使用过滤器总结在Servlet中配置和使用过滤器主要包括创建过滤器类、配置过滤

正则表达式高级应用与性能优化记录

《正则表达式高级应用与性能优化记录》本文介绍了正则表达式的高级应用和性能优化技巧,包括文本拆分、合并、XML/HTML解析、数据分析、以及性能优化方法,通过这些技巧,可以更高效地利用正则表达式进行复杂... 目录第6章:正则表达式的高级应用6.1 模式匹配与文本处理6.1.1 文本拆分6.1.2 文本合并6

python与QT联合的详细步骤记录

《python与QT联合的详细步骤记录》:本文主要介绍python与QT联合的详细步骤,文章还展示了如何在Python中调用QT的.ui文件来实现GUI界面,并介绍了多窗口的应用,文中通过代码介绍... 目录一、文章简介二、安装pyqt5三、GUI页面设计四、python的使用python文件创建pytho

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss