C++ 赋值重载运算符(overloaded operator)operator关键字

重载运算符

  • 重载运算符的本质是函数,其名字由operator关键字后接表示要定义的运算符的符号组成

  • 因此,赋值运算符就是一个名为operator=的函数。

  • 类似于任何其他的函数,重载运算符函数也有一个返回类型和一个参数列表。

  • 重载运算符的参数是表示重载运算符要去操作的运算对象。对于某些运算符,包括赋值运算符,都必须定义为成员函数。

运算符重载

运算符重载是C++中的一种特性,它允许我们为自定义数据类型(如类和结构)定义运算符的行为。这意味着我们可以使用现有的运算符来操作我们定义的类型,使代码更加直观和易于理解。

让我们从一个简单的示例开始,创建一个名为“Fraction”的分数类,我们将重载加法运算符(+)来处理两个分数的相加。

#include <iostream>

class Fraction {
public:
    // 构造函数
    Fraction(int numerator, int denominator) : numerator_(numerator), denominator_(denominator) {}

    // 获取分子
    int GetNumerator() const {
        return numerator_;
    }

    // 获取分母
    int GetDenominator() const {
        return denominator_;
    }

    // 重新定义 Fraction 这个类型的 + 运算符。
    Fraction operator+(const Fraction& other) const {
        int commonDenominator = denominator_ * other.denominator_;
        int newNumerator = (numerator_ * other.denominator_) + (other.numerator_ * denominator_);

        return Fraction(newNumerator, commonDenominator);
    }

private:
    int numerator_; //分子
    int denominator_; //分母
};

int main() {
    Fraction frac1(1, 2);
    Fraction frac2(1, 3);

    Fraction result = frac1 + frac2; // 使用重载后的加法运算符

    std::cout << "Result: " << result.GetNumerator() << "/" << result.GetDenominator() << std::endl;
    return 0;
}

  • 在这个例子中,我们定义了一个名为Fraction的类,它有两个私有成员变量:numerator_(分子)和denominator_(分母)。我们还定义了一个名为operator+的成员函数,它接受一个Fraction对象的引用作为参数,并返回一个新的Fraction对象。这个函数的实现是根据两个分数的加法规则计算出新的分子和分母。

  • 在main()函数中,我们创建了两个Fraction对象,并使用重载的加法运算符(+)将它们相加。最后,我们将结果打印到控制台。

  • 这只是一个简单的示例,C++允许我们重载许多不同的运算符,例如-、*、/、%、==、!=、<、>、<=、>=、++、--、+=、-=、*=、/=、%=、&、|、^、~、<<、>>、>>=、<<=、!、&&、||、[]、()、->、->*、,和new、delete、new[]、delete[]等等。

需要遵守的原则

  • 当重载运算符时,请确保您遵循一些基本原则:
  1. 保持操作符的语义:尽量让重载的运算符具有类似的行为和语义,以避免引入混淆或误导性的代码。

  2. 不要滥用运算符重载:虽然运算符重载可以让代码更易读,但不当使用会导致代码难以理解。请确保重载的运算符适用于您的类,并确保其实现与期望的行为一致。

  3. 使用成员函数和非成员函数进行重载:某些运算符应该作为类的成员函数重载(例如 +=、-=),而另一些运算符应该作为非成员函数重载(例如 +、-)。这取决于运算符的语义以及您希望在类之外使用哪些重载运算符。

以下是另一个Fraction类的示例,这次我们将添加一个友元函数来重载输出运算符(<<):

#include <iostream>
#include <string>
using namespace std;
class Fraction {
public:
    Fraction(int numerator, int denominator) : numerator_(numerator), denominator_(denominator) {}

    int GetNumerator() const {
        return numerator_;
    }

    int GetDenominator() const {
        return denominator_;
    }

    Fraction operator+(const Fraction& other) const {
        int commonDenominator = denominator_ * other.denominator_;
        int newNumerator = (numerator_ * other.denominator_) + (other.numerator_ * denominator_);

        return Fraction(newNumerator, commonDenominator);
    }

    // 重载输出运算符(友元函数)
    friend std::ostream& operator<<(std::ostream& os, const Fraction& fraction);

private:
    int numerator_;
    int denominator_;
};

// 实现重载输出运算符(非成员函数)
std::ostream& operator<<(std::ostream& os, const Fraction& fraction) {
    os << fraction.numerator_ << "/" << fraction.denominator_;
    return os;
}

int main() {
    Fraction frac1(1, 2);
    Fraction frac2(1, 3);
    cout<<"frac1 = "<<frac1<<endl;
    cout<<"frac2 = "<<frac2<<endl;
    Fraction result = frac1 + frac2;

    std::cout << "Result = " <<frac1<<" + "<<frac2<<" = "<< result << std::endl; // 使用重载的输出运算符
    return 0;
}
  • 在这个例子中,我们添加了一个名为operator<<的友元函数,用于重载输出运算符。这使得我们可以直接在std::cout语句中输出Fraction对象,而不需要调用GetNumerator()GetDenominator()函数。

总之,运算符重载是C++中一种强大的特性,可以让我们为自定义类型定义运算符的行为。请务必合理地使用这个特性,以便编写出易于阅读和理解的代码。

忽如其来的问题

问题描述

  • 在这个例子中:
Fraction operator+(const Fraction& other) const {
        int commonDenominator = denominator_ * other.denominator_;
        int newNumerator = (numerator_ * other.denominator_) + (other.numerator_ * denominator_);

        return Fraction(newNumerator, commonDenominator);
    }
  • 这个重载 + 运算符函数,它只有一个传入参数。

  • 而C++Prime5中的Sale_item这个头文件中,同样重载 + 运算符函数为什么就有两个传入参数呢?

Sales_item operator+(const Sales_item &lhs, const Sales_item &rhs)
{
    Sales_item ret(lhs);
    ret += rhs;
    return ret;
}
  • 这是为什么呢?

问题解答

  • 这个区别是因为两个示例中运算符重载的实现方式不同。第一个例子中的operator+是一个成员函数,而第二个例子中的operator+是一个非成员函数。让我们详细讨论一下这两种实现方式的区别。

成员函数重载:

  • 当运算符重载为类的成员函数时,它只需要一个参数,因为调用该运算符的对象(也就是离 + 号最近的那个调用对象)隐式地成为操作数。在第一个示例中,Fraction operator+(const Fraction& other) const是一个成员函数,它的调用方式如下:
Fraction result = frac1 + frac2;
  • 在这里,frac1是调用运算符的对象,它隐式地成为操作数之一,而frac2是作为参数传递给函数的另一个操作数。
  • 最后呢这个函数的返回值作为一个整体,被赋值给result的这个变量。

非成员函数重载:

  • 当运算符重载为非成员函数时,它需要两个参数,分别表示运算符的左操作数和右操作数。通常,非成员函数重载会声明为类的友元函数,以便它能访问类的私有成员。在第二个示例中,Sales_item operator+(const Sales_item &lhs, const Sales_item &rhs)是一个非成员函数(可能是友元函数),它的调用方式如下:
Sales_item result = item1 + item2;
  • 在这里,item1和item2分别作为lhs和rhs参数传递给运算符重载函数。

总之,成员函数重载和非成员函数重载的主要区别在于参数的数量和调用方式。成员函数重载隐式地将调用对象作为操作数之一,因此只需要一个参数;而非成员函数重载需要显式地传递两个操作数作为参数。两种方法都有各自的优点和适用场景,具体取决于您的需求和设计。

问题再次深究
  • 问:当frac1是调用运算符的对象,它隐式地成为操作数之一的时候,它的值不会被改变吗?

  • 答:当frac1作为调用运算符的对象隐式地成为操作数之一时,它的值通常不会被改变,除非运算符的实现特意要修改它。在您之前提到的Fraction类示例中,operator+成员函数是const成员函数,这意味着它不允许修改调用对象的状态(即不会修改对象的数据成员)。因此,在这种情况下,frac1的值不会被改变。
    以下是该示例的代码片段:

    Fraction operator+(const Fraction& other) const {
    	int commonDenominator = denominator_ * other.denominator_;
    	int newNumerator = (numerator_ * other.denominator_) + (other.numerator_ * 	denominator_);
    
     	return Fraction(newNumerator, commonDenominator);
    }
    
  • 在这个operator+实现中,我们只是使用frac1和other(即frac2)的值来计算新的分子和分母,然后创建一个新的Fraction对象来表示结果。frac1和frac2本身的值保持不变。

  • 当使用这个重载运算符时,例如:

    Fraction result = frac1 + frac2;
    
  • result将是一个新的Fraction对象,它包含了frac1和frac2相加的结果,而frac1和frac2的值不受影响。

  • 问:也就是说,operator+ 这个重载操作符函数,隐式的将frac1作为参数然后与参数frac2进行一系列操作后,将这个运算结果返回出去,然后result就会把这个返回结果复制下来,作为自己的初始值,对吗?

  • 答:是的,您的理解是正确的。operator+重载运算符函数将frac1隐式地作为操作数之一,并将frac2作为参数传递。然后,它对这两个操作数执行一系列操作,计算它们的和。最后,它创建一个新的Fraction对象来表示结果,并将这个新对象返回。

  • 当您执行以下代码时:

    Fraction result = frac1 + frac2;
    
  • operator+的返回结果会被赋值给result,这样result就会具有frac1和frac2相加得到的新值。需要注意的是,frac1和frac2的值在这个过程中保持不变。

总结

我原来在看C++Primer5的时候,第一开始就给我一堆我看不懂的代码,然后其中最看不懂的就是这个operator关键字,原来我还不知道是啥意思,今天我死磕了好几个小时,终于给我弄懂了!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

阿宋同学

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

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

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

打赏作者

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

抵扣说明:

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

余额充值