代码改变世界

白话C++系列(32) -- 运算符重载

2016-07-03 21:47  Keiven_LY  阅读(1014)  评论(0编辑  收藏  举报

运算符重载

什么是运算符重载呢?所谓运算符重载,就是给原有运算符赋予新的功能比如说,加好(+)是用来做两个数字相加操作的(如:1+1=2),但是,我们往往用加号来让两个字符串作拼接(如:慕+课=慕课),那么,这个时候就是给加号做了运算符的重载。我们来看一个常见的例子:

在这个例子当中,我们就使用了加号去连接多个字符串,使其拼接成一个字符串,而且,我们在打印的时候,也可以将拼接好的字符串直接打印出来,那么这个字符串就进行了多个运算符的重载(加号运算符做了重载,输出运算符也做了重载,等号运算符也做了重载)。那么,问题是:这些重载究竟是怎么做的呢?后续课程为大家一一讲解。

我们再来看另外一个例子:

在这个例子中,有两个坐标,这两个坐标其实也是可以相加的,相加之后你二舅会形成一个新的坐标。可是,这两个坐标相加对于加号本身来说,并不具备这样的功能。为了能让其具备这样的功能,我们就可以通过运算符重载来实现。同时,如果我们想直接输出一个坐标,我们也可以通过重载输出运算符来实现。

下面我们来看一看运算符重载的本质!

其实,运算符重载的本质就是:函数重载它并没有什么神秘的地方。

下面介绍一下,定义运算符重载的关键字:operator。

那么,运算符重载其实有很多种,包括:一元运算符重载、二元运算符的重载等。

一元运算符重载

对于一元运算符的重载,在这里,我们举两个例子:

-(负号)的重载

++符号的重载

所谓负号,就是将减号(-)写在某个对象的前面,把它当作一元运算符(所谓一元运算符,就是这个符号只与一个操作数进行运算,比如说:加号其实就是一个二元运算符,因为加号需要由两个操作数来进行运算,而正号,即就是将加号放在一个操作数的前面,那么它就是一个一元运算符),使这个对象进行取反运算。

++符号也是一个一元运算符,可是++符号的运算可以放在操作数的前面,也可以放在操作数的后面。

负号的重载方式:一种是友元函数重载,一种是成员函数重载。友元函数重载,换句话说,就是在类当中去定义一个友元函数,这个友元函数是一个全局函数,用这个友元函数来做运算符的重载,从而实现一个符号多了一项功能。成员函数的重载,其实就是在定义一个类的成员函数。

负号(-)成员函数重载

我们来看这个例子,在这个例子当中,我们定义了一个Coordinate坐标类。如果我们想要对负号(-)做成员函数的重载,我们就应该写成Coordinate& operator-(),因为是一元运算符,而且它是作为类的成员函数存在,所以这里不需要传入任何的参数。实现的时候怎么来做呢?如下

请大家注意,其实我们不传入参数作为一个普通的成员函数来说,它还是有一个隐性的this指针的,而这个隐性的this指针其实就是它的操作数,那么我们就可以将每一个数据成员取反后,再重新复制给它,使得它的所有的数据成都由正变成了负,或者是都由负变成了正,然后将(*this)作为返回值返回出去即可。我们再来看一看如何使用,如下:

需要在对象的前面写一个负号(-),就会使得当前的这个Coordinate对象所有的值都会取反,就相当于使用Coordinate这个对象coor1去调用operator-()这个函数,也就是说这两者是等价的。当计算机遇到这样的时候,就会将其解释成一个函数的调用。

负号(-)友元函数重载

下面我们再来看一下友元函数重载是怎样实现负号运算符重载的。

我们来看这个例子,还是Coordinate这个坐标类,但是这个时候,我们使用友元申明:通过friend关键字来申明一个全局函数operator-,那么这个时候我们需要传入一个参数,这个参数就是Coordinate的一个引用,其返回值也是一个Coordiante的引用。实现的时候我们需要通过这个引用变量分别对它的每一个数据成员取反,然后再赋值给其本身,最后将(*this)返回回去,如下:

调用的时候,当我们给对象coor1取反的时候,计算机就会将其解释成operator-(),并且传入对象coor1,即:operator-(coor1),如下:

请大家比对成员函数重载和友元函数重载的区别。对于成员函数重载,调用的时候是coor1.operator-(),而对于友元函数重载,这里写的是operator-(coor1),这是有本质区别的。

接下来我们说一说++符号的重载,其分为前置++符号重载和后置++符号重载。所谓前置++符号重载,就是将++写在操作数的前面,这一点在C语言当中都已经学习过

++运算符前置重载

我们通过例子来说明这个问题。如果想要做++运算符的前置重载,并且把它当作成员函数来操作的话,我们可以这样来写:

这里注意:因为++是一个一元运算符,所以operator++()中也不用传入任何参数。

那么,定义的时候,我们作为一个成员函数来进行定义,使它的每一个数据成员都做++操作,最后将(*this)返回出去,如下:

这里可以想见一下,外面接收到的值其实就是++之后的值了。如果我们++coor1,就相当于coor1.operator++()的操作,即:

++运算符后置重载

那该如何实现后置++呢?计算机要对前置++和后置++进行区分。所以后置++是需要特别注意的。定义的时候,返回值不再是引用,而是Coordinate的一个对象,并且operator++()中必须要传入一个int,即一定要是operator++(int),这里的int是一个标识,它标识当前的++符号做的是后置重载,如下:

在使用的时候,这里的int的地方并不传入任何值,即便是将来使用传入任何值也没有意义,,因为我们根本就不去使用它,只是一个标识而已。

那么,如何去定义呢??我们要保证有一个旧的值,所以我们要先来定义一个临时对象Coordinate old,然后将当前这个值先保存在old对象当中,最后通过return将这个old返回出去,如下:

如果接收到后置++的值,那么,后置++的值呢,也是没有++之前的值,但是它的下一行代码如果再去使用当前这个对象的时候,其里面的值就已经发生变化了。因为,我们再给old赋完值后呢,当前的这个对象就已经将其当中的数据成员都做了++操作。使用的时候,请大家注意,这个时候是后置++,如下:

当后置++的时候,系统会默认为我们传入一个值,这个值呢,一般来时就是0,它没有什么意义,但是它能够表达出,这是一个在调用后置++的运算。

一元运算符重载代码实践

题目描述:

/*  *********************************************  **/

/* 运算符重载......一元运算符重载

要求:定义一个Coordinate坐标类

    成员函数:构造函数,getX,getY

            数据成员:m_iX,m_iY

       1、负号运算符重载(成员函数、友元函数)

       2、++运算符重载(前置、后置)

*/

/*  *********************************************  **/

程序框架:

头文件(Coordinate.h

#ifndef COORDINATE_H
#define COORDINATE_H

#include<iostream>
using namespace std;

class Coordinate
{
public:
    Coordinate(int x, int y);//构造函数
    int getX();
    int getY();
private:
    int m_iX;
    int m_iY;
};

#endif

源程序(Coordinate.cpp

#include"Coordinate.h"

Coordinate::Coordinate(int x, int y) //将传入的参数x和y分别赋值给数据成员m_iX和m_iY
{
    m_iX = x;
    m_iY = y;
}
int Coordinate::getX()
{
    return  m_iX;
}
int Coordinate::getY()
{
    return  m_iY;
}

下面根据题目描述,首先给大家要演示的是负号的成员函数的重载。

我们再回到Coordinate.h文件,在Coordinate.h当中,我们需要先将它的声明写出来。那么,对于负号运算符来说,它返回出来的应该是它本身,这样的话呢,它还可以再进行负号运算符的运算。怎样让它返回出来是对象本身呢??我们把它写成一个引用,即:Coordinate &operator-(),括号里不需要加任何的参数,如下:

#ifndef COORDINATE_H
#define COORDINATE_H

#include<iostream>
using namespace std;

class Coordinate
{
public:
    Coordinate(int x, int y);//构造函数
    Coordinate& operator-();
    int getX();
    int getY();
private:
    int m_iX;
    int m_iY;
};

#endif

我们再转到Coordinate.cpp中去实现它。那么,作为负号运算符重载呢,其实就是将它里面的m_iX和m_iY这两个坐标分别取负值,怎么来写呢?如下:

Coordinate& Coordinate::operator -()
{
    m_iX = -m_iX;  //this ->m_iX = -this->m_iX ;
    this ->m_iY = -this->m_iY; // m_iY = -m_iY;
    return  *this;
}

接下来我们调到demo.cpp文件下面,先实例化一个对象coor1,并且传入两个初值1和3,也就是说,它的横坐标是1,它的纵坐标是3。接下来我们通过cout来打印一下它的横纵坐标。通过调用getX来取得它的横坐标,通过调用getY来取得它的纵坐标。接下来就是我们的重点了,首先对coor1取负号(其实这里就相当于调用了coor1.operator-()),这样的效果就相当于将(*this)取反,同时将当前的这个对象的横纵坐标都做了取负号的操作。那么,接下来我们就可以通过cout去打印coor1的横纵坐标了,如下:

#include<iostream>
#include"Coordinate.h"

using namespace std;

int main()
{
    Coordinate coor1(1,3);
    cout << coor1.getX() <<","<< coor1.getY() << endl;
    -coor1; //coor1.operator-();
    cout << coor1.getX() <<","<< coor1.getY() << endl;
    system("pause");
    return 0;
}

然后我们按F5,看一看运行结果:

从运行结果我们可以看到,在没有取负号之前,coor1的坐标是(1, 3),取负号之后变成了(-1, -3)。

我们看到,当前我们去定义的时候采用的是引用这种方式,接下来,我们要给大家体验一下这种引用方式的好处。

什么好处呢?如果我们在这取了一次负号,那么我们再给它取一次负号会怎样呢?学过数学的我们肯定知道,负负得正,如下:

int main()
{
    Coordinate coor1(1,3);
    cout << coor1.getX() <<","<< coor1.getY() << endl;
    -(-coor1);//coor1.operator-();
    cout << coor1.getX() <<","<< coor1.getY() << endl;
    system("pause");
    return 0;
}

我们来看一看是不是负负得正的效果呢?如下:

我们看到,取两次负号的结果就是两次打印结果是一样的,也就是如我们所想的负负得正的效果。

接下来我们给大家演示一下友元函数的负号运算符的重载。我们需要将成员函数运算符重载先注释掉。趁现在注释掉成员函数运算符重载后,我们也要给大家演示一个现象。我们看到刚才对coor1取负号是行得通的,现在当运算符重载去掉之后,对coor1取负号后,再来看一看是否行得通?我们按F7后,显示如下:

我们可以看到,编译出错了,告诉我们一元”-”这个负号没有定义运算符或者是预定义运算符可接收的类型转换。这里说这么多,其实就一个意思:当前的对象coor1是无法通过负号直接进行操作的,如果想要可以操作,必须是它可以认识的,想要认识,就要加上运算符重载。由于运算符重载的代码我们已经注释掉了,所以计算机编译时就会报错了。

接下来,我们采用友元函数运算符进行重载。

我们调到Coordinate.h文件当中,修改如下:

#ifndef COORDINATE_H
#define COORDINATE_H

#include<iostream>
using namespace std;

class Coordinate
{
    friend Coordinate& operator-(Coordinate &c);//这里需要插入一个参数,其实就是在成员函数当中传入的this,此时体现上就是一个Coordinate对象:Coordinate c即可;如果为了传递效率,这里也可以写成一个引用形式
public:
    Coordinate(int x, int y);//构造函数
    //Coordinate &operator-();
    int getX();
    int getY();
private:
    int m_iX;
    int m_iY;
};

#endif

然后我们写出它的定义,调到Coordinate.cpp文件当中,修改如下:

#include"Coordinate.h"

Coordinate::Coordinate(int x, int y) //将传入的参数x和y分别赋值给数据成员m_iX和m_iY
{
    m_iX = x;
    m_iY = y;
}
int Coordinate::getX()
{
    Return  m_iX;
}
int Coordinate::getY()
{
    return  m_iY;
}
//Coordinate &Coordinate::operator -()
//{
//    m_iX = -m_iX;  //this ->m_iX = -this->m_iX ;
//    this ->m_iY = -this->m_iY; // m_iY = -m_iY;
//    return *this;
//} 

Coordinate& operator-(Coordinate &c)
{
    c.m_iX = -c.m_iX;
    c.m_iY = -c.m_iY;
    return c;
}

接下来再调到demo.cpp文件当中,先不作任何修改,看看编译是否通过

我们看到,编译是没有问题的

接下来再按F5,看一看运行的结果:

我们看到,与成员函数的重载运行结果是一样的。

接下来再来看一下++符号的前置运算符重载和后置运算符重载。

我们跳到Coordinate.h文件当中,前置++我们需要返回来的仍然是Coordinate这个当前对象指针:Coordinate& operator++();因为是一元运算符,所以在这个成员函数重载的时候,这里不需要传入参数。

然后,我们需要去实现它。如何来实现呢?

Coordinate& Coordinate::operator++()
{
    m_iX++; //++m_iX;
    m_iY++; //++m_iY;
    return *this;
}

接着转到demo.cpp中,如下:

#include<iostream>
#include"Coordinate.h"

using namespace std;

int main()
{
    Coordinate coor1(1,3);
    cout << coor1.getX() <<","<< coor1.getY() << endl;
    ++coor1;
    cout << coor1.getX() <<","<< coor1.getY() << endl;

    //-coor1; //coor1.operator-();
    //cout << coor1.getX() << "," << coor1.getY() << endl;
    system("pause");
    return 0;
}

我们来看一下运行结果:

我们看到,经过++之后,坐标由原来的(1,3)变成了(2,4),显然++是起到了作用。

接下来,我们再看一下后置++。

后置++与前置++有什么区别呢?首先,我们来看一下后置++重载的声明:

Coordinate operator++(int);这里有一个参数,其实这个参数只是一个标识而已,只起到告诉编译器这是一个后置++重载的作用;另外,这里的返回值不再跟之前一样返回一个引用了,而是返回的是一个Coordinate对象。这是为什么呢?我们来想一想前置++和后置++的区别:前置++后,此时这个表达式的值就是这个而对象++之后的值了;后置++后,此时这个表达式的值是这个对象++之前的值,当我们下一行代码再去访问这个对象的时候,就是++之后的值。所以,我们在实现的时候要进行区分开来。

Coordinate Coordinate::operator++(int) //后置++的实现
{
    Coordinate old(*this); //这里使用了默认的拷贝构造函数
    this->m_iX++;
    this->m_iY++;
    return old; //注意:这里return出去的是old,不是this
}

我们再回到demo.cpp中,

#include<iostream>
#include"Coordinate.h"

using namespace std;

int main()
{
    Coordinate coor1(1,3);
    cout << coor1.getX() <<","<< coor1.getY() << endl;
    cout << (coor1++).getX() <<","  ;
    cout << (coor1++).getY() << endl;

    system("pause");
    return 0;
}

我们按F5看一下运行结果:

我们看到打印出的是由原来的(1,3)变成了后来的(1,4),这是为什么呢?

(1,3)输出是没有问题的,因为这是原有的输入;(1,4)的输出是为什么呢?这是因为,当我们cout << (coor1++).getX() <<","  ;之后,返回的是当前的数值,而之后再次调用这个对象时,就是++之后的值了,所以当后面一句cout << (coor1++).getY() << endl;后,就得到的是3加1后的值,即4。

二元运算符重载

加号(+)成员函数重载

我们来看下面的这个例子

在这个类当中,我们除了声明了Coordinate的构造函数之外,还声明了Coordinate operator+();从声明形式来看,它是一个成员函数。这里需要注意的是:在这个成员函数中需要传入一个参数(const Coordinate &coor),我们如何来定义operator+这个函数呢?

我们看到,定义的时候首先需要定义一个临时的Coordinate对象temp,然后传入的这个coor对象的横坐标要与当前对象的横坐标相加,然后将相加之后的值赋值给这个临时对象temp的横坐标(纵坐标处理与横坐标一样),最后将这个临时对象temp作为返回值返回出去。那么,在使用的时候,我们就可以这样来写:

首先,我们定义一个coor1坐标对象,它传入的是3和5,即coor1的横坐标是3,纵坐标是5,同理,coor2的横坐标是4,纵坐标是7,然后我们再定义一个结果,这个结果是coor3对象,用coor3来接收coor1与coor2相加的和。请大家注意:这个对方的加号(+)就已经用到了运算符重载,其就相当于coo1.operator+(coor2)这里需要注意的是:其实作为函数重载来说,加号(+)作为二元运算符在它传入的另外一个参数的前面其实是有一个隐形参数this的,那这个this就相当于传入的第一个参数coor1

加号(+)友元函数重载

友元函数重载相对于成员函数重载来说,其更能说明问题。如下:

友元函数重载,大家可以看到,我们需要通过friend关键字来声明一个友元函数,并且这个友元函数是在Coordinate这个类当中声明的友元函数,它的两个参数分别是:const Coordinate &c1和const Coordinate &c2。这里我们可以写上const,也可以不写const。如果我们写上const的话,大家可以想象一下,在当我们去定义函数的时候,我们就无法在函数当中去修改c1和c2的值了。大家想一想加法,在加法当中,我们让一个加数和另外一个加数去相加的时候,我们与而不希望在加的过程中去修改加数本身的值,所以加上const其实是一种设计上的规范。然后,我们再来看一看它的实现:

我们看到,在实现加号友元函数重载的时候,我们也需要先定义一个临时的Coordinate对象temp,然后我们传入两个参数c1和c2,将c1的横坐标与c2的横坐标相加后赋值给临时对象temp的横坐标,c1的纵坐标与c2的纵坐标相加后赋值给临时对象temp的纵坐标,最后将这个临时对象temp作为返回值返回出去。那么,我们在mian函数中去使用的时候,其实与加号的成员函数重载是一样的,即

输出符号(<<)友元函数重载

我们在定义输出符号运算符的时候,可以写成这样:

在定义输出符号(<<)的友元函数重载的时候,其友元函数的返回值必须是ostream&,其传入的第一个参数也必须是ostream的一个引用,第二个参数是要进行输出的对象。当我们去实现这个函数的时候,我们怎么来写呢?

我们看到,是用out替代了原来的cout的位置,替代之后,其他部分的写法不变,最后,也是必须的,要将out返回出去。接下来,我们看一看如何来使用:

如果我们定义一个Coordinate的对象coor,其横坐标是3,纵坐标是5,那么我们通过cout就可以直接输出coor了。如果我们不进行<<运算符的重载,这样写肯定是错误的。如果我们进行了<<元素安抚的重载,这样写就相当于operator<<(cout, coor)。

通过这个例子,其实我们从侧面也能够理解cout是什么呢?它就是一个对象,是一个什么对象呢?就是一个ostream类型的对象

接下来我们来考虑一个问题:输出运算符可以采用成员函数重载吗?

针对这个问题,我们从成员函数重载的特点来给大家说一说。如果我们使用成员函数重载,比如说之前提到的加号(+)运算符的成员函数重载,我们一起来回顾一下:在加号运算符当中,我们使用成员函数重载,这个时候需要传入的只有一个参数,这个参数其实是第二个加数,而第一个加数默认就是当前这个对象。可是,对于输出运算符来说,我们可以看到,第一个参数必须是ostream,这就意味着不能是这个this指针,也就不能是当前这个对象,所以,当我们去重载输出运算符的时候,是绝对不可以通过成员函数去进行重载的,而必须采用友元函数进行重载

索引符号([ ])成员函数重载

索引运算符更多的是运用在数组当中,这里我们先把它运用到Coordinate这个类当中。我们来看一看如何来定义:

声明的时候,我们需要将索引运算符作为一个成员函数放到Coordinate这个类当中,定义方法同样是用关键字operator,然后再加索引运算符([ ])。因为是索引,所以我们需要传入一个int类型的索引index,并且返回一个整型值。接下来,我们来看一看其实现方法:

函数是这样定义的:传入的参数index,先判断一下它等不等于0,如果它等于0,那么我们就将横坐标的值返回出去;如果它等于1,那么我们就将纵坐标的值返回出去;如果它是其他值,我们这里暂时没有进行处理。实际上,我们应该抛出一个异常。

接下来,我们来看一看它的使用:

如果我们实例化了一个Coordinate的对象coor,纯如两个值:3和5。3是coor的横坐标,5是coor的纵坐标。如果我们通过cout来输出coor的0号元素,即:cout << coor[0],那么实际上就是输出横坐标值;如果我们输出coor的1号元素,即:cout << coor[1],那么实际上就是输出纵坐标值。大家可以看一看,当我们去调用coor,然后接索引的时候,其实就相当于调用coor.operator[](0)或者coor.operator[](1)。

下面我们来思考一个问题:索引运算符可以采用友元函数重载吗?答案也是否定的。原因是:友元函数重载,它的第一个参数可以是成员函数中的那个this指针,也可以是其他的值,可是,作为索引运算符来说,它的第一个参数必须是this指针,因为,只有第一个参数是this指针,才能够传入索引,才能够使得这个索引所表达的是当前这个对象的当中的成员。比如说,在我们这个例子当中,第一个参数一定时this指针,它表达的就是Coordinate的一个对象,接下来传入的0或1,所表达的就是传入的this指针所指向的这个对象当中的0号元素或者是1号元素,所谓0号元素就是当前这个对象的横坐标值,1号元素就是当前这个对象的纵坐标值。所以,对于索引运算符必须采用成员函数进行重载,而无法采用友元函数进行重载。

二元运算符重载代码实践

题目描述:

/*   *****************************************  */

/*  运算符重载----二元运算符重载

要求:定义Coordinate坐标类

    成员函数:构造函数、getX、getY

            数据成员:m_iX、m_iY

      1、加号(+)运算符重载(成员函数、友元函数)

      2、输出运算符(<<)重载

      3、索引运算符([])重载

*/

/*   *****************************************  */

头文件(Coordinate.h)

#ifndef COORDINATE_H
#define COORDINATE_H

class Coordinate
{
public:
    Coordinate(int x, int y);
    Coordinate operator+(Coordinate &c); //申明加号(+)运算符成员函数重载
    int getX();
    int getY();
private:
    int m_iX;
    int m_iY;
};

#endif

源程序(Coordinate.cpp)

#include"Coordinate.h"

Coordinate::Coordinate(int x, int y)
{
    m_iX = x;
    m_iY = y;
}

int Coordinate::getX()
{
    return  m_iX;
}

int Coordinate::getY()
{
    return  m_iY;
}

Coordinate Coordinate::operator+(Coordinate &c) //加号(+)运算符成员函数重载实现方法
{
    Coordinate temp(0,0);
    temp.m_iX = this->m_iX + c.m_iX;
    temp.m_iY = this->m_iY + c.m_iY;
    return temp;
}

主调程序(demo.cpp)

#include<iostream>
#include"Coordinate.h"

using namespace std;

int main()
{
    Coordinate coor1(1,3);
    Coordinate coor2(2,4);
    Coordinate coor3(0,0);
    coor3 = coor1 + coor2;
    cout << coor3.getX() <<","<< coor3.getY() << endl;

    system("pause");
    return 0;
}

我们按F5,看一看运行结果:

从运行结果可以看到,我们这里的加号(+)运算符的成员函数重载是ok的。那么,我们再来看一看加号(+)运算符友元函数的重载是如何实现的。

我们需要在以上代码中,将成员函数重载的代码注释掉。然后,在Coordinate.h文件中,通过friend关键字来声明一个友元函数:friend Coordinate operator+(Coordinate &c1, Coordinate &c2);接着在Coordinate.cpp文件中去实现这个友元函数,如下:

Coordinate operator+(Coordinate &c1, Coordinate &c2) //加号(+)运算符友元函数重载实现方法
{
    Coordinate temp(0,0);
    temp.m_iX = c1.m_iX + c2.m_iX;
    temp.m_iY = c1.m_iY + c2.m_iY;
    return temp;
}

demo.cpp文件不变,我们来按一下F5,看一看运行结果与之前的成员函数重载是否一样:

我们看到的结果也是(3,7),与之前是一样的。

接下来,我们来看一看输出运算符(<<)的重载。根据我们之前的客商所讲,输出运算符的重载必须是友元函数的重载。另外,还要注意,它的返回值是一个ostream类型,即声明为:friend ostream& operator<<(ostream &output, Coordinate &coor);接着在Coordinate.cpp文件中去实现这个友元函数,如下:

ostream& operator<<(ostream &output, Coordinate &coor)//输出运算符友元函数重载实现方法
{
    //注意:这里不需要写成coor.getX()或coor.getY()了,
    //因为coor是一个友元,直接访问太的数据成员就可以了
    output<<coor.m_iX <<","<<coor.m_iY;
    return output;
}

然后,转到demo.cpp中,修改如下:

int main()
{
    Coordinate coor1(1,3);
    Coordinate coor2(2,4);
    Coordinate coor3(0,0);
    coor3 = coor1 + coor2;
    //cout << coor3.getX() << "," << coor3.getY() << endl;
    cout << coor3 << endl;

    system("pause");
    return 0;
}

我们按F5看一看运行结果:

我们看到是ok的,直接输出了3和7,那么它的输出效果与之前用cout分别输出(cout << coor3.getX() << "," << coor3.getY() << endl;)的效果是一样的。另外,需要提醒大家的是,在Coordinate.h文件中,我们用到了ostream,就需要在一开始的地方就应该包含iostream头文件(#include<iostream>),包含完之后,还需要声明一下它的命名空间(using namespace std;)。

最后,我们来看一下索引运算符的重载。

我们之前已经学过,对于索引运算符,其必须要使用成员函数重载。在这里,其返回值是int类型,因为我们传入索引0的时候,想要返回的是横坐标值,传入索引1的时候,想要返回的是纵坐标的值。声明如下:int operator[](int index);接着在Coordinate.cpp文件中去实现这个成员函数,如下:

int Coordinate::operator[](int index) //索引运算符成员函数重载实现方法
{
    if(0 == index)
    {
        return m_iX;
    }
    if(1 == index)
    {
        return m_iY;
    }
    //注意:这里如果既不是0,也不是1,就需要我们抛出异常处理
    //这里抛出异常不是我们的重点,就忽略异常情况
}

然后,转到demo.cpp中,修改如下:

int main()
{
    Coordinate coor1(1,3);
    Coordinate coor2(2,4);
    Coordinate coor3(0,0);
    coor3 = coor1 + coor2;
    //cout << coor3.getX() << "," << coor3.getY() << endl;
    //cout << coor3 << endl;
    cout << coor3[0] << endl;
    cout << coor3[1] << endl;

    system("pause");
    return 0;
}

我们按F5看一看运行结果:

我们看到,输出结果分别是3和7,可见,我们的索引运算符重载也是可以实现的。