大家好,在这一小节中呢,我们开始了一个新的概念。
那么就是关于C++语法当中的运算符重载。
我们首先来看一下,相关的一些基本概念。
那么运算符呢,其实大家非常熟悉的。
我们在C++语法当中呢,已经预定义了非常多的一些运算符。
那么它呢,主要是用来对数据进行运算操作的。
我们有非常熟悉到的这些加、减、乘、除、求于,
等等等等一系列这样一些运算符。那么这些运算符呢,就都一个特别
基本的特点。那么就是它只能用于非常基本的那些数据类型。
比方说:整型、实型、字符型、逻辑型等等。
但是呢,我们在C++当中呢 提供了一种新的数据抽象的手段,也就是允许
用户呢去自己定义一个新的数据类型。我们把它称之为叫做“类”。
那么通常呢我们是去设计、调用类的成员函数
来去操作相应这个新类型类里面去定义的对象。
啊,去操作这些相应的对像。但是有些时候呢,我们会发现说
直接使用成员函数呢,在操作对象的时候会显得的很不方便。
比方说我们在数学上,可以直接把两个复数进行加减等计算。
那么C++当中呢,如果我们直接利用+号或者是-号
去操作一个复数类对应生成的对象的时候,就会变得不可以。
那么这时候呢,如果我们要去自己写一个函数呢,当然也可以去做这些相应的操作。
那么我们希望呢,能够像使用数学上的这种加减符号一样,
依旧可以去操作不同类型的这样的一个数据。那么这时候呢,我们就
需要去使用运算符重载。
运算符重载呢,主要就是希望能够对抽象的数据类型也能够使用
C++原有提供的那些传统的运算符。这样会有
什么样的好处呢?首先呢,它会使得代码看起来呢非常的简洁;
并且呢也容易理解。啊,始终的传统原来大家约定俗称的一些符号。
那比方我们举个例子。
我们有两个复数的对象,complex_a和complex_b这样两个
复数类生成的对像。我们呢希望就直接利用+号,
就把就把这两个复数类产生的对像呢
进行相加。那么得到的效果是什么呢?仍然得到了一个新的复数的对象。那么,它的实部呢,
就是之前两个复数类对象的实部的相加,虚部呢也想相应的虚部的相加。
那么运算符重载呢它实际上说白了,就是对
已有的那些运算符赋予更多多重的含义。啊,可能有一个运算符
它能够去处理不同类型的数据; 那么它可以支持这种不同类型的行为。
它不再是只能把简单的那些整型相加、 实型相加,而是变成可以把一些我们用户自己定义的
不同的类型呢都利用原来传统的运算符连接在一起。
所以呢,我们说运算符重载的目的呢,去
扩展了C++中提供的那些运算符的适用范围。
并且呢,能够用于类所表示的抽象的那些数据类型。
那么我们看,如果说呢我们对于
同一个运算符但是对于不同类型的操作数 那么它所发生的行为是不同的。
但是呢,它使用的,操作这个符呢,运算符呢是一,同样的。
那么运算符重载这样的一个实现呢
它的实质上呢,实际上就是利用了函数重载这样的一个技术。
那么我们去重载运算符的时候呢,我们通常呢 规定需要使用这样的一个表达形式的一个函数。
就是我们利用operator这样去标记需要重载的运算符。
那么后面呢可以跟着一个形参表,那么这个形参表呢用来
传递的就是相应这个操作运算符连接的这个操作数。
然后呢,再给出一个相应的返回值来定义 我们这个运算符进行重返的一个函数。
我们具体看一下,在程序编译的时候呢,我们实际上
会首先将这个含有运算符的表达式
对应转换成为是什么呢?转换成为一个对运算符函数
的一个调用。啊,我们刚才定义了那个函数,operator对应的那个运算符的那个函数。
完了之后呢,我们会去把这个运算符连接的这个操作数,比方说:a+b
对吧?b就是这个运算符。那么a
和b这样两个数呢我们把它称之为叫做
操作数。这两个操作数呢就会作为运算符函数的参数来进行传递。
那么当着运算符多次被重载的时候呢, 我们可以根据实际实参的类型
去决定具体是调用哪一个运算符的函数。啊, 我们可能
为了支持很多种不同的运算,所以呢我们会撰写虽然对于同一个
运算符,我们可能会写若干个不同的运算符函数,
那么具体要使用哪一个呢?我们就要去看a和b的类型。
如果a 和 b是复数,那么我们就去调用复数的那个运算符加相加的那个复数;
如果他是其他类型的话呢,我们就可以调用其相应的类型来进行计算。
那么运算符自身呢是可以被重载为一个普通的函数的。
同时呢,它也可以被重载为类的一个成员函数。这两种实践方式都可以。
我们来具体看一下,当这个运算符呢被重载为普通函数的时候,
那么我们有一个complex的复数类, 这个复数类呢当然它包含了一个
构造函数。在这个构造函数里头呢去初始化实部和虚部。
同时呢,我们还有一个 定义了两个这样的成员变量,分别是定义实部和虚部。
那么我们希望能够实践呢这个运算符重载+号去可以连接两个复数,直接进行相加。
那么我们把它声明为是一个普通的函数的话呢,我们就可以去定义
operator+,啊,重载这个+号。
那么它这个参数对应是什么呢?它对应了分别是这个+号前后的两个操作数: a和b。
那么它们的类型呢是complex的一个引用,啊,最为const的类型传进来。
通过计算呢我们希望输出的仍然是一个复数类型的一个
对象,所以呢,返回值也是complex类型的。
我们在这个重载的函数里面完成的事儿呢,其实就是非常简单的吧!
a和b对应这两个对象的实部进行相加,以及它们的虚部进行相加。
我们看到说呢,我们定义好了这个样的运算符重载的函数之后,
如果我们有相应的两个对象-a和b, 啊。
a的实部是1,虚部是2 。b的实部是2,虚部是3 ;
以及我们定义去放置累加和的这个复数的对象 称之为c
。那么应为有了这样的一个 运算符重载+号的函数,所以我们就可以
直接在程序里面这么写c=a+b。
对吧?那么这个函数实际上呢,对应可以认为相当于是什么呢?
相当于就是我们去调用了operator
{{BLANK}}+号这样的一个函数
那么传进来的这个参数呢,分别就是两个操作数a和b。
那么这两个,这个函数的标用
和c=a+b其中的这个a+b的过程呢 这两个是相互等价的。
那么我们要注意,当你重载成一个普通函数的时候,那么
参数的个数就是运算符的目数。啊,所谓运算符的目数就是说
a+b那么它是一个2目的一个运算。啊,有两个操作数。
所以呢,因为它要把这两个操作数全部都传递进来,
所以它是一个操作数和参数相等个数这样的一个表示。
那么当这个运算符被重载为是成员函数的时候呢
它会略略有一点不同。我们刚才看到对于一个普通函数来讲,
它会有两个操作数。那么对一个成员函数来讲的话,因为它前面有一个对像;
也就是说,这个a+b这样的一个双目运算,
我们如果把a认为是一个对象来讲的话,那么,
+b作为一个成员函数,那么它实际上调用的
是一个成员函数的操作。比如说a,operator +。
所以呢,对于成员函数来讲,它就不再是一个
两参数的一个传递;而只传递后面
那个具体的操作数。啊,所以呢我们去重载
运算符变成成员函数的时候,那么它只需要传进来一个参数就可以完成。
所以我们说,参数的个数呢是运算符数目-1。
那么具体的实践其实也是一样的。啊,我们在实现
这个成员函数的时候,我们只需要把这个当前对象的实部 去累加上我们传入的这个参数的实部。
作为实部。而把当前对象的虚部 去累加上传入这个对象的虚部就可以了。
那么相同的,operator-号也是作为跟+号 一样的一个操作。只不过呢就是做了一个减法的一个操作。
那么我们看到,如果我们定义了一个 类的对象,分别是x和y; 以及是z。
那么如果我们希望能够把y和z相加附给x,或者是
把y和z相减附给x。那么我们就因为重载了+/-这两个运算符
我们在这里呢就可以直接利用这样等式来进行表达。那么注意,
这里头的x=y+z和x=y-z又是分别是什么呢?
其实它就是表示了是 x=y.operator。