一文学懂C++运算符重载

C++运算符重载是指在C++中,程序员可以重新定义已有的运算符,使其能够适用于自定义的数据类型。通过运算符重载,程序员可以使自定义类型的对象进行类似于内置类型的运算操作,从而增强程序的可读性和可维护性。

以上是比较官方一点的定义,我在初学C++时就有过的一个疑问,例如

#include<iostream>
#include<vector>
using namespace std;
int main()
{
    vector<int> a;
    for (int i = 0; i < 10; i++) a.push_back(i);
    for (int i = 0; i < 10; i++) cout << a[i]<<" ";
​
    return 0;
}

 

在上面这段代码中,vector<int> a,并不是数组,为什么可以通过a[index]的方式去访问呢,就是因为STL在实现容器类时,对操作符进行了重载,我们才得以利用这种方式进行访问。

实际上,运算符重载就是函数,知识调用函数的方式就是我们不用再利用函数名去调用函数了,直接利用我们重载的运算符就可以调用到对应的函数实现我们的功能。

我们我们只要交接以下几种运算符重载的方式就可以满足我们绝大部分的运用场景,我会用一个日期类来举例进行解释。

class Date
{
​
    //友元
    friend ostream& operator<<(ostream& out, const Date& d);
    friend istream& operator>>(istream& in, Date& d);
public:
    Date(int year = 7900, int month = 1, int day = 1);
    void Print() const;
    int GetMonthDay(int year, int month) const;
    bool operator==(const Date& d) const;
    bool operator<(const Date& d) const;
    bool operator<= (const Date & d) const;
    bool operator>(const Date& d) const;
    bool operator>=(const Date& d) const;
    bool operator!= (const Date& d) const;
    Date& operator+=(int day);
    Date operator+(int day) const;
    Date& operator-= (int day);
    Date operator- (int day) const;
    int operator- (const Date& d) const;
    Date operator++();
    Date operator++(int);
    //区分前置后置
    Date& operator--();
    Date operator--(int);
private:
    int _year;
    int _month;
    int _day;
​
};

运算符重载的几种主要方式

1.类成员函数重载:

通过在类中定义运算符函数,可以重载大部分的运算符,这也是运算符重载的主要方式。这些函数在类中定义接受一个参数,通常是右操作数,但是对于有些运算符需要两个。例如加法运算符:

Date Date::operator+(int day) const
{
    Date tmp(*this);
    tmp += day;
    return tmp;
​
}

该运算符重载函数,是给日期加上一个天数,得到一个新的日期,所以返回类型是Date类型,给定一个整形的参数,但是对于这种类成员函数重载还有一个隐形的参数,就是调用该函数的对象本身,必须是运算符的左值,例如Date a(2023,2,3); a = a+100;就是给日期a加上100天,返回一个新的日期赋值给a。在表达式a = a+100;中在+号左边的a也是该函数的操作数之一。

在类成员函数的定义中含有一个比较重要和混淆的点就是,如何区分前置++和后置++,前面我们说隐形参数都做左值,但是前缀后缀自增自减运算符时没有参数的,所以我们区分它们的方式是通过参数列表中是否有一个 int 类型的形参来区分的。

//前置--
Date& Date::operator--()
{
​
    *this -= 1;
    return *this;
}
//后置--
Date Date::operator--(int)
{
    Date tmp(*this);
    *this -= 1;
    return tmp;
}

但是有时候我们需要将对象本身作为操作符的右值所以该种方法并不适用所有的情况,还需运用到另外一种方法,所以就有了下面解释的友元函数重载。

2.友元函数重载

友元函数重载为什么能解决要将调用运算符的对象做右值的情况呢,因为它已经不是成员函数了,没有隐形的参数,所以就不会使调用运算符的对象必须作为左值,但是非对象成员函数会衍生出一个新的问题,那就是无法访问调用对象的成员变量,因为对象成员变量都是私有的,所以就引申出了友元函数,它既不是成员函数,但是又可以访问对象的私有成员变量。我们利用重写输入输出流来详细了解一下:

inline ostream& operator<< (ostream & out, const Date & d)
{
    out << d._year << "年" << d._month << "月" << d._day << "日" << endl;
    //为什么返回out呢  当连续调用时执行完当下的可以继续往后执行
​
    return out;
}
inline istream& operator>>(istream& in, Date& d)
{
    in >> d._year >> d._month >> d._day;
    return in;
}

我们看上面的参数,有两个参数,为了使调用输入输出流对象时,能和基类型一样,我们使它的返回类型仍然为输入输出流对象,是为了可以像基类型一样能够连续的调用调用。

3.全局函数重载运算符

全局函数与友元函数类似,但它们不是类的成员函数。它们可以访问类的公共成员和友元函数,但不能访问类的私有成员。例如,对于加法运算符,全局函数的定义为:

class Vector {
public:
    friend Vector operator+(const Vector& v1, const Vector& v2);
};
​
Vector operator+(const Vector& v1, const Vector& v2) {
    Vector result;
    // ...
    return result;
}

所以全局函数和友元函数基本上没有什么区别,只是说友元函数可以是全局函数、类的成员函数或另一个类的成员函数。

总结

运算符重载的主要知识点大概就是这些,大家可以利用以上的日期类自己进行实现并测试一下。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值