C++重载运算符详解

 C++允许我们为我们的类重定义或重载大部分C++内置的运算符。这样我们的类就可以通过这些运算符进行一些操作。比如加减乘除,赋值比较等。

重载的运算符是带有特殊名称的函数,函数名是由关键字 operator 和其后要重载的运算符符号构成的。

与其他函数一样,重载运算符有一个返回类型和一个参数列表。

    比如我们要给复数类Complex重载加法运算符:

Complex operator+(Complex& a) //成员函数

    这是个定义为成员函数的例子,如果我们要定义为非成员函数,则应有两个参数。

Complex operator+(Complex& a,Complex& b)   //非成员函数

其中参数为进行该运算时的变量类型,函数返回值是运算的结果。比如例子中的复数相加后那么返回的当然也应该是一个复数。

下面是演示代码:

成员函数实现:

#include<iostream>
using namespace std;
class Complex
{
    double real,imag;
public:
    Complex(double r,double m)    //构造函数
    {
        real=r;
        imag=m;
    }
    Complex operator+(Complex& a)     //成员函数重载+运算符
    {
        return Complex(real+a.real,imag+a.imag);
    }
    void show()
    {
        cout<<real<<' '<<imag<<'i'<<endl;
    }
};
int main()
{
    Complex Cmp1(1,2);
    Cmp1.show();
    Complex Cmp2(3,4);
    Cmp2.show();
    Complex Cmp3=Cmp1+Cmp2;   //将Cmp1+Cmp2的结果赋给Cmp3
    Cmp3.show();
    return 0;
}

友元函数实现:

#include<iostream>
using namespace std;
class Complex
{
    double real,imag;
public:
    Complex(double r,double m)  //构造函数
    {
        real=r;
        imag=m;
    }
    friend Complex operator+(Complex& a,Complex& b)    //非成员函数的重载+运算符
    {
        return Complex(a.real+b.real,a.imag+b.imag);
    }
    void show()
    {
        cout<<real<<' '<<imag<<'i'<<endl;
    }
};
int main()
{
    Complex Cmp1(1,2);
    Cmp1.show();
    Complex Cmp2(3,4);
    Cmp2.show();
    Complex Cmp3=Cmp1+Cmp2;     //将Cmp1+Cmp2的结果赋给Cmp3
    Cmp3.show();
    return 0;
}

输出结果:

1 2i
3 4i
4 6i

没错就是这么简单。

但是其实程序在编译时,成员函数版的重载编译器将 Cmp1+Cmp2 替换为了

Cmp1.operator+(Cmp2)

友元函数版的重载替换为了

operator+(Cmp1,Cmp2)

我们将程序改一下。

int main()
{
    Complex Cmp1(1,2);
    Cmp1.show();
    Complex Cmp2(3,4);
    Cmp2.show();
    Complex Cmp3= Cmp1.operator+(Cmp2);  //非成员函数版应为  Complex Cmp3= operator+(Cmp1,Cmp2);
    Cmp3.show();
    return 0;
}

输出结果相同

可以看到重载运算符其实没多高端,就是调用了个函数,和一般的函数没太大区别。

接下来重载一下<<运算符让这个类可以用cout直接输出。


如果我们定义成成员函数,那么最后调用的就是上面那个样子,就是Cmp1.operator<<(参数)了

如果我们要用cout输出,应该是cout.operator<<(Cmp)

这样看来我们是要定义成ostream类的成员函数了,但这显然是不行的,我们不能改ostream的源码,而且也不符合 面向对象 的要求。


所以我们使用第二种,定义为友元函数

首先当然是要定义成Complex类的友元函数,但是ostream类的对象也是这个运算符的参数,

需不需要定义成ostream类的友元函数呢?


定义为Comlex的友元函数是因为输出时,输出的是Complex类的私有成员需要友元函数才能访问,

但是不需要访问ostream类的私有成员所以ostream只需要作为参数传入即可

下面是完整的代码实现:

#include<iostream>
using namespace std;
class Complex
{
    double real,imag;
public:
    Complex(double r,double m)            //构造函数
    {
        real=r;
        imag=m;
    }
    Complex operator+(Complex& a)                //重载加法,返回Complex类的对象
    {
        return Complex(real+a.real,imag+a.imag);
    }
    friend ostream& operator<<(ostream& os,Complex& a)  //重载<<运算符
    {
        os<<a.real<<' '<<a.imag<<'i';
        return os;
    }
};
int main()
{
    Complex Cmp1(1,2);
    Complex Cmp2(3,4);
    cout<<Cmp1<<endl<<Cmp2<<endl;   //cout的连续输出
    Complex Cmp3=Cmp1+Cmp2;
    cout<<Cmp3<<endl;
    return 0;
}

其中重载的<<运算符的返回值类型是ostream& 是因为我们用cout输出时,经常会有

cout<<变量1<<变量2<<.........<<endl;这样的操作。

就像26行那样

而且使用<<运算符的也可能是ostream的派生类的对象,所以我们要返回引用,使得前后一致。

一些注意事项

  • 要清楚运算符的参数是什么,顺序是什么,以此来写重载运算符的函数,比如我们重载<<运算符的时候
  • 想清楚该操作符需要什么样的返回值,比如加法就返回一个对象,<<返回一个ostream&

最后附上可重载/不可重载的运算符表

下面是可重载的运算符列表:

双目算术运算符 + (加),-(减),*(乘),/(除),% (取模)
关系运算符 ==(等于),!= (不等于),< (小于),> (大于>,<=(小于等于),>=(大于等于)
逻辑运算符 ||(逻辑或),&&(逻辑与),!(逻辑非)
单目运算符 + (正),-(负),*(指针),&(取地址)
自增自减运算符 ++(自增),--(自减)
位运算符 | (按位或),& (按位与),~(按位取反),^(按位异或),,<< (左移),>>(右移)
赋值运算符 =, +=, -=, *=, /= , % = , &=, |=, ^=, <<=, >>=
空间申请与释放 new, delete, new[ ] , delete[]
其他运算符 ()(函数调用),->(成员访问),,(逗号),[](下标)

下面是不可重载的运算符列表:

  • .:成员访问运算符
  • .*->*:成员指针访问运算符
  • :::域运算符
  • sizeof:长度运算符
  • ?::条件运算符
  • #: 预处理符号

猜你喜欢

转载自blog.csdn.net/qq_39027601/article/details/80548661