【C++】运算符重载详解

本文详细介绍了C++中如何通过运算符重载为自定义类型如日期类添加加减运算和比较功能,包括一元和二元运算符重载,以及重点讨论了赋值运算符重载的概念、语法和使用引用参数的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

💗个人主页💗
⭐个人专栏——C++学习
💫点击关注🤩一起学习C语言💯💫

目录

导读

1. 为什么需要运算符重载

2. 运算符重载概念

3. 运算符重载示例

3.1 == 运算符重载

3.2 >或<运算符

4. 运算符重载参数

5. 全局运算符重载函数

6. 赋值运算符重载

6.1 语法及概念

6.2 示例

6.3 为何使用引用


导读

前面我们学习了默认成员函数:构造函数、析构函数和拷贝构造函数。

今天我们来学习赋值运算符重载。

1. 为什么需要运算符重载

我们一般的运算符只能对于数字进行运算,或是比较大小,但是如果我们想要对我们所定义的自定义类型进行运算呢?

为了使自定义类型能够支持运算符操作,可以通过运算符重载的方式来重新定义这些运算符,使其能够在自定义类型上执行特定的操作。

比如我们定义了一个日期类,想要对这个日期类进行加减运算,亦或是比较两个日期的大小,通过运算符重载即可实现。

2. 运算符重载概念

C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其 返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。

函数名字为:关键字operator后面接需要重载的运算符符号。

函数原型:返回值类型 operator操作符(参数列表)

一般来说需要遵循以下几个原则:

  1. 运算符的重载必须定义在类、结构体或枚举中。

  2. 运算符重载函数必须使用特殊的命名约定,以指示要重载的运算符。

  3. 运算符重载函数可以是类的成员函数,也可以是非成员函数。

  4. 运算符重载函数的参数和返回值类型应该与运算符原有的操作数类型相匹配。

  5. 运算符重载函数可以使用其他的运算符或已有的函数来实现其操作。

3. 运算符重载示例

3.1 == 运算符重载

我们来判断两个日期是否相等:

我们需要依次比较年、月、日。

class Date
{
public:
    Date(int year = 1900, int month = 1, int day = 1)
    {
        _year = year;
        _month = month;
        _day = day;
    }

    //operator运算符 做函数名
    bool operator == (const Date& y)
    {
        return _year == y._year
            && _month == y._month
            && _day == y._day;
    }

   
private:
    int _year;
    int _month;
    int _day;
};

int main()
{
    Date d1(2024, 2, 02);
    Date d2(2024, 2, 03);


    cout << d1.operator ==  (d2) << endl;

    return 0;
}

我们知道,运算符重载也是默认成员函数之一,也就是我们不去调用,编译器也会自动帮我们调用。

比如:

class Date
{
public:
    Date(int year = 1900, int month = 1, int day = 1)
    {
        _year = year;
        _month = month;
        _day = day;
    }

    //operator运算符 做函数名
    bool operator == (const Date& y)
    {
        return _year == y._year
            && _month == y._month
            && _day == y._day;
    }

private:
    int _year;
    int _month;
    int _day;
};

int main()
{
    Date d1(2024, 2, 3);
    Date d2(2024, 2, 2);

    cout << d1.operator ==  (d2) << endl;
    cout << (d1 == d2) << endl;
    return 0;
}

3.2 >或<运算符

判断两个日期的大小:

class Date
{
public:
    Date(int year = 1900, int month = 1, int day = 1)
    {
        _year = year;
        _month = month;
        _day = day;
    }

    //operator运算符 做函数名
    bool operator < (const Date& y)
    {
        if (_year < y._year)
        {
            return true;
        }
        else if (_year == y._year)
        {
            if (_month < y._month)
            {
                return true;
            }
            else if (_month == y._month)
            {
                return _day < y._day;
            }
        }
        return false;
    }
private:
    int _year;
    int _month;
    int _day;
};

int main()
{
    Date d1(2024, 1, 28);
    Date d2(2024, 1, 29);

    cout << d1.operator < (d2) << endl;

    cout << (d1 < d2) << endl;
    return 0;
}

4. 运算符重载参数

上述我们的代码明明是对两个日期进行比较,为何只有一个参数呢?

运算符重载函数的参数取决于要重载的运算符的操作数个数和类型。

  1. 一元运算符重载:一元运算符只有一个操作数。在重载一元运算符时,通常将其定义为类的成员函数,没有参数(除了隐式的this指针)。

  2. 二元运算符重载:二元运算符有两个操作数。在重载二元运算符时,可以选择将其定义为类的成员函数或非成员函数。

    • 如果将二元运算符定义为类的成员函数,参数列表将包括一个额外的参数,表示右侧操作数。左侧操作数则是隐式的this指针。

    • 如果将二元运算符定义为非成员函数(全局函数或友元函数),参数列表将包括两个参数,分别表示左侧和右侧操作数。

5. 全局运算符重载函数

我们依旧对比两个日期是否相等,判断大小,注意与上述代码的参数差异。

class Date
{
public:
    Date(int year = 1900, int month = 1, int day = 1)
    {
        _year = year;
        _month = month;
        _day = day;
    }
    //private:
    int _year;
    int _month;
    int _day;
};

//operator运算符 做函数名
bool operator == (const Date& x, const Date& y)
{
    return x._year == y._year
        && x._month == y._month
        && x._day == y._day;
}

bool operator < (const Date& x, const Date& y)
{
    if (x._year < y._year)
    {
        return true;
    }
    else if (x._year == y._year)
    {
        if (x._month < y._month)
        {
            return true;
        }
        else if (x._month == y._month)
        {
            return x._day < y._day;
        }
    }
    return false;
}
int main()
{
    Date d1(2024, 1, 28);
    Date d2(2024, 1, 29);

    cout << operator == (d1, d2) << endl;
    cout << operator < (d1, d2) << endl;

    cout << (d1 == d2) << endl;
    cout << (d1 < d2) << endl;
	return 0;
}

6. 赋值运算符重载

6.1 语法及概念

赋值运算符重载是一种特殊的运算符重载,用于在自定义的类中重载"="运算符,使其能够对类对象进行正确的赋值操作。

赋值运算符重载的语法如下:

class ClassName {
public:
    ClassName& operator=(const ClassName& other) {
        // 执行赋值操作的代码
        return *this;
    }
};

在赋值运算符重载函数中,通常需要执行以下操作:

  1. 检查是否是自我赋值,即当前对象和要赋值的对象是否是同一个对象。如果是同一个对象,则直接返回当前对象,避免不必要的操作。

  2. 进行属性的深拷贝,将要赋值的对象的属性逐个复制给当前对象的属性。

  3. 返回当前对象的引用。

6.2 示例

class Date
{
public:
    Date(int year = 1900, int month = 1, int day = 1)
    {
        _year = year;
        _month = month;
        _day = day;
    }
    void Print()
    {
        cout << _year << '/' << _month << '/' << _day << endl;
    }
    Date& operator=(const Date& d)
    {
        if (this != &d)
        {
            _year = d._year;
            _month = d._month;
            _day = d._day;
        }
        return *this;
    }

private:
    int _year;
    int _month;
    int _day;
};

int main()
{
    Date d1(2024, 2, 01);
    Date d2(2024, 2, 02);
    Date d3(2024, 2, 03);

    d1 = d2 = d3;
    d1.Print();
    d2.Print();
    d3.Print();

    return 0;
}

6.3 为何使用引用

  1. 引用参数:赋值运算符需要修改当前对象的值,而不是创建一个新的对象。因此,使用引用参数,可以直接修改当前对象而不是在函数内部创建一个副本。

  2. 返回this指针:赋值运算符一般返回当前对象的引用,即*this。这样可以实现连续赋值操作,例如 a = b = c。通过返回this指针,可以链式调用赋值运算符。

### C++ 运算符重载概述 C++ 允许对已有的运算符进行重新定义,以便这些运算符可以用于用户自定义的数据类型。这种特性被称为运算符重载[^2]。当运算符应用于类类型的对象时,可以通过运算符重载为其赋予特定的行为。 #### 类型及其应用范围 对于关系运算符(如 `<`、 `>`、 `<=`、 `>=` 和 `==` 等),C++ 支持对其进行重载以实现两个类对象之间的比较逻辑[^1]。除此之外,还有其他多种类型的运算符可被重载,比如算术运算符、下标运算符和赋值运算符等。 #### 实现方式 运算符重载本质上是一个特殊的函数形式,其名称由关键字 `operator` 加上所要重载的具体运算符号组成。这类函数拥有自己的返回类型与参数列表;一元运算符接受单个参数,二元运算符则需接收两个参数。值得注意的是,如果将运算符重载声明为类内部的方法,则第一个隐含的参数即为当前实例本身(`this`)指向的对象,这使得实际传递给方法体内的显式参数数目减少了一个[^3]。 下面给出几个具体的例子来展示不同种类运算符是如何被重载并使用的: #### 示例代码片段 ##### 1. 关系运算符重载示例 假设有一个表示二维向量(Vector2D) 的类, 可以为此类添加相等判断的功能: ```cpp class Vector2D { public: double x; double y; bool operator==(const Vector2D& other) const { // 成员函数版本 return (x == other.x && y == other.y); } }; ``` 上述代码实现了两个Vector2D 对象之间是否相同的判定功能。 ##### 2. 算术运算符重载示例 继续沿用上面的例子,现在增加加法的支持: ```cpp // 非成员函数版本 Vector2D operator+(const Vector2D& v1, const Vector2D& v2){ return Vector2D{v1.x + v2.x , v1.y + v2.y }; } ``` 这段程序展示了如何利用全局作用域下的非成员函数来进行两矢量求和的操作。 ##### 3. 下标运算符重载示例 为了方便访问数组中的元素或者模拟容器行为,还可以考虑如下做法: ```cpp class ArrayWrapper { private: int* data; size_t length; public: ... int& operator[](size_t index){ // 提供读写权限 if(index >= length || index < 0) throw std::out_of_range("Index out of range"); return data[index]; } const int& operator[](size_t index)const{ //只读模式 if(index >= length || index < 0) throw std::out_of_range("Index out of range"); return data[index]; } }; ``` 这里分别提供了两种不同的索引器版本——一种适用于修改数据的情况,另一种则是针对不允许改变内容的情形设计而成。
评论 23
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

流浪者与猴

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值