C++学习笔记----8、掌握类与对象(六)---- 操作符重载(2)

1.3、第三次尝试:全局operator+

        隐式转换允许你使用operator+成员函数给SpreadsheetCell对象加上int与double。然而,这个操作符不是双向的,如下代码所示:

	aThirdCell = myCell + 5.6;
	aThirdCell = myCell + 4;
	aThirdCell = 5.6 + myCell; // FAILS TO COMPILE!
	aThirdCell = 4 + myCell;   // FAILS TO COMPILE!

        当SpreadsheetCell对象在操作符左侧的时候可以很好地进行隐式转换,但是当在右边的时候就不灵光了。另外假定是双向的,其实也有问题。问题就是operator+成员函数必须在SpreadsheetCell对象上进行调用,该对象必须在operator+的左手边。c++语言就是这么定义的。所以是没有办法让operator+成员函数按那种方式工作的。

        然而,如果把类内的operator+成员函数用全局的operator+函数替换,不与任何特定对象紧密绑定在一起,就可以解决这个问题了。函数看起来像这样:

SpreadsheetCell operator+(const SpreadsheetCell& lhs, const SpreadsheetCell& rhs)
{
	return SpreadsheetCell { lhs.getValue() + rhs.getValue() };
}

        需要在模块接口文件中声明该操作符并export出来:

export class SpreadsheetCell
{
    /* Omitted for brevity */
};

export SpreadsheetCell operator+(const SpreadsheetCell& lhs, const SpreadsheetCell& rhs);

        现在所有的四个前面的相加操作都可以按你想要的结果工作了。

	aThirdCell = myCell + 5.6;    // works fine
	aThirdCell = myCell + 4;    // works fine
	aThirdCell = 5.6 + myCell; // works fine
	aThirdCell = 4 + myCell;   // works fine

        你可能会想,如果按下面的代码写会有什么结果:

aThirdCell = 4.5 + 5.5;

        它会正常编译并执行,但是不会调用你写的operator+。它会执行正常的double相加4.5与5.5,结果是下面的中间语句:

aThirdCell = 10;

        为了使这个赋值语句好好干活,应该在右手边有一个SpreadsheetCell对象。编译器发现有一个非显式的用户定义的构造函数使用一个double参数,会使用这个构造函数隐式地将double值转换成一个临时的SpreadsheetCell对象,然后会调用赋值操作符。

2、重载算术操作符

        现在你理解了怎么写operator+,那剩下的基本算术操作术就很直接了。下面是+,-,*,与/的声明,可以用<op>来替换+,-,*,与/,结果就是四个函数。也可以重载%,但是对于保存在SpreadsheetCell中的double值是讲不通的,没必要凑数了。

export class SpreadsheetCell { /* Omitted for brevity */ };
export SpreadsheetCell operator<op>(const SpreadsheetCell& lhs,
    const SpreadsheetCell& rhs);

        operator-与operator*的实现与operator+的实现类似,所以就不赘述了。对于operaotr/,稍有点儿不同,记住要检查是否被零除。如果检测到被零除要抛出一个例外:

SpreadsheetCell operator/(const SpreadsheetCell& lhs, const SpreadsheetCell& rhs)
{
	if (rhs.getValue() == 0) {
		throw invalid_argument { "Divide by zero." };
	}
	return SpreadsheetCell { lhs.getValue() / rhs.getValue() };
}

                c++不要求在operator*真正实现乘,在operator/中实现除,等等。你可以在operator/中实现乘,在operator/中实现除,等等。然而,那样会非常地令人迷惑,没有道理这么做啊。只要有可能,在实现中用通常的用过的操作符的意思就行了。

注意:在c++中,不要改变操作的运算优先级。例如,*与/要比+与-早检查。一旦运算的优先级定了,用户定义的操作符唯一需要做的事就是去实现。c++也不允许你发明新的操作符号或者改变操作符的参数数量。我们以后还会再详细讨论操作符重载。

2.1、重载算术缩写操作符

        除了简单的算术操作符,c++提供了像+=与-=这样的缩写操作符。你可能想当然地认为在类中写了operator+,它就会提供operator+=。对不起,你没有这么走运。你不得不显式地重载缩写算术操作符。这些操作符与基本的算术操作述不同,它们改变了操作符左手边的对象而不是生成一个新对象。第二个细微的不同是,与赋值操作符相似,它们产生了一个指向被改变对象的引用结果。

        算术缩写操作符总是要求左手边的类的对象,所以要把它们写成成员函数,而不是全局函数。下面是SpreadsheetCell类的定义:

export class SpreadsheetCell
{
public:
	SpreadsheetCell& operator+=(const SpreadsheetCell& rhs);
	SpreadsheetCell& operator-=(const SpreadsheetCell& rhs);
	SpreadsheetCell& operator*=(const SpreadsheetCell& rhs);
	SpreadsheetCell& operator/=(const SpreadsheetCell& rhs);
    // Omitted for brevity
}

        operator+=的实现,其它的类似。

SpreadsheetCell& SpreadsheetCell::operator+=(const SpreadsheetCell& rhs)
{
	set(getValue() + rhs.getValue());
	return *this;
}

        缩写的算术操作符是基本算术与赋值操作符的组合。有了前面的定义,你可以写出下面的代码:

	SpreadsheetCell myCell { 4 }, aThirdCell{ 2 };
	aThirdCell -= myCell;
	aThirdCell += 5.4;

        但是,你不能写出下面这样的代码(有这种想法也是很奇葩!)

5.4 += aThirdCell;

        注意:当同时有正常的与缩写版本的某个操作符时,推荐使用正常的那个而不是缩写版本的,以避免代码重复。

        下面是一个例子:

SpreadsheetCell operator+(const SpreadsheetCell& lhs, const SpreadsheetCell& rhs)
{
	auto result{ lhs };  // Local copy
	result += rhs;       // Forward to +=()
	return result;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

王俊山IT

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

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

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

打赏作者

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

抵扣说明:

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

余额充值