# 十.运算符重载

将系统自定义的运算符用于用户自定义的类型,运算符重载的实质是函数重载

格式:返回类型 operator <符号> (参数表)

{ 重载函数体 }

不能重载的运算符

成员访问运算符 成员指针运算符 域操作运算符 条件运算符 空间计算运算符
. ***** : : ? : sizeof

注意

  1. 不允许定义新的运算符
  2. 不能改变该运算符操作数(对象)的个数
  3. 不能改变该运算符的优先级别和结合性
  4. 应该符合实际需要,重载的功能应该与运算符原有的功能相似,避免没有目的的使用重载运算符

对于同一个重载函数,要么定义为成员函数,要么定义为友元函数,不能二者都定义,否则容易引起二义性

# 1. 运算符重载为友元函数

声明格式:friend 返回类型 operator 运算符(参数表);

函数定义返回类型 operator 运算符(参数表)

{ 函数体 }

#include<iostream>
using namespace std;
class Complex
{
    private:
    double real,image;
    public:
    Complex(double r,double i):real(r),image(i){}
    void show()     //输出虚数的函数
    {
        if(image > 0)
        {
            if(image == 1)
                cout<<real<<"+"<<"i"<<endl;
            else
                cout<<real<<"+"<<image<<"i"<<endl;
        }
        else if(image < 0)
        {
            if(image == -1)
                cout<<real<<"-"<<"i"<<endl;
            else
                cout<<real<<image<<"i"<<endl;
        }
        else
            cout<<real<<endl;
    }
    friend Complex operator+(const Complex &c1,const Complex &c2);//声明友元函数
    friend bool operator==(const Complex &c1,const Complex &c2);
};

Complex operator+(const Complex &c1,const Complex &c2) //重载+运算符
{
    Complex t;
    t.real = c1.real + c2.real;
    t.image = c1.image + c2.image;
    return t;  //返回类对象
}
bool operator==(const Complex &c1,const Complex &c2) //重载==运算符
{
    if(c1.real == c2.real && c1.image == c2.image)
        return true;
    else
        return false;
}

int main()
{
    Complex c1(1,1),c2(2,2);
    c1.show();
    c2.show();
    Complex c3 = c1 + c2;                 //隐式调用
    //Complex c3 = operator+(c1,c2);      //显式调用
    if(c1 == c2)                          //调用==重载函数
        cout<<"两个复数相等"<<endl;
    else
        cout<<"两个复数不相等"<<endl;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

# 2. 运算符重载为成员函数

  1. 如果是重载为双目运算符,就只要设置一个参数作为右侧运算量,而左侧运算量就是该对象本身

  2. 如果是重载单目运算符,就不必另外设置参数,运算符的操作量就是对象本身

    函数定义返回类型 operator 运算符(参数表)

    { 函数体 }

#include<iostream>
using namespace std; 
class Complex
{
    private:
    double real,image;
    public:
    Complex(double r,double i):real(r),image(i){}
    void show()     //输出虚数的函数
    {
        if(image > 0)
        {
            if(image == 1)
                cout<<real<<"+"<<"i"<<endl;
            else
                cout<<real<<"+"<<image<<"i"<<endl;
        }
        else if(image < 0)
        {
            if(image == -1)
                cout<<real<<"-"<<"i"<<endl;
            else
                cout<<real<<image<<"i"<<endl;
        }
        else
            cout<<real<<endl;
    }
    
    Complex operator+(const Complex &c1)    //重载+运算符函数,只有一个参数
    {
        Complex t;
        t.real = this->real + c1.real;
        t.image = this->image + c1.image;
        return t;
    }
    Complex operator==(const Complex &c1)    //重载==运算符函数
    {
        if(this->real == c1.real && this->image == c1.image)
            return true;
        else
            return false;
    }
};

int main()
{
    Complex c1(1,1),c2(2,2);
    c1.show();
    c2.show();
    Complex c3 = c1 + c2;                 //隐式调用
    //Complex c3 = operator+(c1,c2);      //显式调用
    if(c1 == c2)                          //调用==重载函数
        cout<<"两个复数相等"<<endl;
    else
        cout<<"两个复数不相等"<<endl;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56

# 3. 几种常用的运算符重载

# (1)输入>>和输出<<运算符

只能采用友元形式

格式:ostream &operator<<( ostream &, const 类对象引用); //ostream &的作用是可以实现连续输出,参数中ostream的引用不能用const修饰,因为向流中写入数据会改变流的状态

istream &operator>>( istream &, 类对象引用);

#include<iostream>
using namespace std;
class Complex
{
    ... // 内容省略
    friend ostream &operator<<(ostream &myout,const Complex &c);//声明输出重载函数
    friend istream &operator>>( istream &myin,Complex &c);//声明输入重载函数
};

ostream &operator<<(ostream &myout,const Complex &c)//定义输出运算符重载函数
{
    if(c.image > 0)
        {
            if(c.image == 1)
                cout<<c.real<<"+"<<"i"<<endl;
            else
                cout<<c.real<<"+"<<c.image<<"i"<<endl;
        }
        else if(c.image < 0)
        {
            if(c.image == -1)
                cout<<c.real<<"-"<<"i"<<endl;
            else
                cout<<c.real<<c.image<<"i"<<endl;
        }
        else
            cout<<c.real<<endl;
    return myout;         //返回ostream的引用
}
istream &operator>>( istream &myin,Complex &c)//定义输入运算符重载函数
{
    cin>>c.real>>c.image;
    return myin;          //返回istream的引用
}

int main()
{
    Complex c1,c2;
    ...
    //cin.operator>>c1>>c2;   //显式调用
    cin>>c1>>c2;
    cout<<c1<<c2;//若没有定义输出重载函数,则错误,不能输出Complex类;但现在可以正常输出。//隐式调用
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

# (2)自增运算符++(前置和后置)

后置参数表有一个int型参数,但是前置没有;后置会在函数体里定义一个临时类对象,返回的是临时类对象;前置返回的是当前对象

自减运算符一样

#include<iostream>
using namespace std;
class Complex
{
    ...
    Complex operator++()    //定义前置++重载
    {
        this->real++;
        this->image++;
        return *this;
    }
    Complex operator++(int)   //定义后置++重载
    {
        Complex temp = *this;
        this->real++;
        this->image++;
        return temp;
    }
};

int main()
{
    Complex c1,c2;
    ...
    //Complex c4 = c1.operator++();    //显式调用
    Complex c4 = ++c1;     //隐式调用
    Complex c5 = c1++;
    ...
    return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

# (3)赋值操作符=

  • 赋值运算符“=”是双目运算符

  • 如果不定义自己的赋值运算符函数,那么编译器会自动生成一个默认的赋值运算符函数

  • 赋值运算符函数必须是类的成员函数不允许重载为友元函数

  • 赋值运算符函数不能被派生类继承

    与上面赋值运算符函数类似

    例1

    #include<iostream>
    using namespace std;
    class Complex
    {
        ...
        /*void operator=(const Complex &c)   //类型不能为void,因为如果是c1=c2=c3;那么c2=c3返回void,c1不能等于void,所以应为Complex类
        {
            this->real = c.real;
            this->image = c.image;
        }*/
        Complex operator=(const Complex &c)   
        {
            this->real = c.real;
            this->image = c.image;
            return *this;         //系统可以自己写(自带),返回this指针
        }
    };
    
    int main()
    {
        Complex c1,c2;
        ...
        c1 = c2 = c3;//都为c3的值
        ...
        return 0;
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26

    例2

    #include<iostream>
    #include<string>
    using namespace std;
    class String
    {
        char *sbuf;   //用来存放字符串指针
        int length;   //表示字符串长度
        public:
        String()      //不带参数的构造函数,创建一个空串
        {
            length = 0;
            sbuf = new char;
            sbuf[0] = '\0';
        }
        String(char *s)  //用字符串初始化,串拷贝
        {
            length = strlen(s);
            sbuf = new char[length + 1];  //开辟空间,对一个空间放'\0'字符串的结束符
            strcpy(sbuf,s);
        }
        ~String()
        {
            delete[] sbuf;   //回收空间
        }
        void show()     //输出字符串
        {
            cout<<sbuf<<endl;
        }
        String(const String &temp) //拷贝构造函数     //深拷贝
        {
            length = temp.length;
            sbuf = new char[length + 1];
            strcpy(sbuf,temp.sbuf);
        }
        String& operator=(const String &s)  //第一个&的作用是返回当前对象时不会调用拷贝构造函数,防止函数调用开销过大
        {
            if(this == &s)  //防止自赋值(如s1 = s1;)
                return *this;
            
            length = s.length;
            //sbuf = s.sbuf;     //不能直接赋值,因为当前对象是先创建再赋值的,创建时已经申请了一个空间,若现在直接赋值,则当前的sbuf指向被复制的sbuf的空间,那么先前的sbuf无指针指向,而被复制的空间有两个指针指向,在析构时会出现错误
            delete []sbuf;       //要先删除当前对象的sbuf的空间
            sbuf = new char[length + 1];//再申请与被复制空间等大的空间,使当前的sbuf等于它
            strcpy(sbuf,s.sbuf);//再拷贝字符串
            return *this;   //返回当前对象
        }
    };
    int main()
    {
        String s1("Hello");//调用String(char *s);
        String s2 = s1;    //调用String(const String &temp);
        String s3;         //调用String();
        s3 = s1;    //重点 //调用赋值运算符函数String& operator=(const String &s);
        s3 = s2 = s1;//连续赋值  //调用String& operator=(const String &s);
        s1.show();
        s2.show();
        s3.show();
        return 0;
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
上次更新时间:: 2/9/2025, 9:12:58 PM