C++_Primer_Plus之操作符重载

2023-12-13 21:50:17

介绍重载操作符

C++允许程序与重载操作符,从而定义自己的操作符的行为。重载操作符可以是类成员函数或全局函数。

C++允许将操作符重载扩展到用户定义的类型,例如,允许使用+将两个对象相加。编译器将根据操作数的数目和类型决定使用哪种加法定义。

通常,我们要将两个数组进行相加,是这样实现:

for(int i = 0;i < 10;i++)
	a[i] = b[i] + c[i];

但是通过重载+操作符,我们就可以这样写

a = b + c;

这种简单的加法表示法隐藏了内部机理,并强调了实质,这是OOP的另一个目标。

要重载操作符,需要使用被称为操作函数的特殊函数形式。操作函数的格式如下:

operator op(argument-list)

其中,op是要重载的操作符。例如:operator +()重载+操作符、
operator -()重载-操作符。

op必须是一个有效的C++操作符,不能是虚构的。例如,不能有
operator @()这样的函数,因为C++没有@操作符。

例如,现在有一个Salesperson类,并为它定义了一个operator +()成员函数,以重载+操作符,以便将两个Salesperson类的销售额(Salesperson类的成员变量)加在一起。如果A、B、C是Salesperson类对象,则可以写成这样的表达式

A = B + C;

编译器发现,操作数是Salesperson类对象,因此使用相应的操作符函数替换上述操作符:
相当于

A = B.operator+(C);

然后该函数将隐式地使用B(因为它调用了方法),而显式地使用C对象(因为它被作为参数传递),来计算总和,并返回这个值。当然最重要的是,可以使用简便的+操作符表示法,而不必使用笨拙的函数表示法。

计算时间:一个操作符重载范例

如果今天早上在Priggs的账户上花费了2小时35分钟,下午又花费了2小时40分钟,则总共花了多少时间呢?

常规写法

// Time.h

#pragma once

#include <iostream>

class Time
{
public:

	Time();

	Time(int _h, int _m = 0);

	void AddMin(int _m);

	void AddHour(int _h);

	void Reset(int _h = 0, int _m = 0);

	Time Sum(const Time& t) const;

	void Show() const;

private:

	int hours_;

	int minutes_;

};
// Time.cpp

#include "Time.h"

Time::Time()
{
    hours_ = minutes_ = 0;
}

Time::Time(int _h, int _m)
{
    hours_ = _h;

    minutes_ = _m;
}

void Time::AddMin(int _m)
{
    minutes_ += _m;
    hours_ += minutes_ / 60;
    minutes_ %= 60;
}

void Time::AddHour(int _h)
{
    hours_ += _h;
}

void Time::Reset(int _h, int _m)
{
    minutes_ = _m;
    hours_ = _h + minutes_ / 60;
    minutes_ %= 60;
}

Time Time::Sum(const Time& t) const
{
    Time sum;

    sum.minutes_ = minutes_ + t.minutes_;
    sum.hours_ = hours_ + t.hours_ + sum.minutes_ / 60;
    sum.minutes_ %= 60;

    return sum;
}

void Time::Show() const
{
    std::cout << hours_ << "小时" << minutes_ << "分钟" << std::endl;
}

示例中,我们定义了AddHour、AddMin、Show、Sum的方法分别用于添加小时、添加分钟、显示花费时间、相加的操作。

我们主要看Sum(),在Sum方法中,对相加后的时间做了调整。

测试:

// main.cpp

#include "Time.h"

int main()
{
	Time first(1, 20);
	Time second(2, 30);

	std::cout << "第一次花费时间:";
	first.Show();

	std::cout << "第二次花费时间:";
	second.Show();

	Time total = first.Sum(second);
	std::cout << "总计花费时间:";
	total.Show();

	system("pause");
	return 0;
}

输出结果:

第一次花费时间:1小时20分钟
第二次花费时间:2小时30分钟
总计花费时间:3小时50分钟

重载操作符为类成员写法

将Time类的Sum函数替换成重载+操作符。

即将Sum方法替换为

Time Time::operator +(const Time& t) const
{
    Time sum;

    sum.minutes_ = minutes_ + t.minutes_;
    sum.hours_ = hours_ + t.hours_ + sum.minutes_ / 60;
    sum.minutes_ %= 60;

    return sum;
}

这样我们在客户端的用法是这样:

// Time total = first.Sum(second);
	Time total = first + second;
	std::cout << "总计花费时间:";
	total.Show();

输出结果和上面一样。

我们也可以将

Time total = first + second;
替换成
Time total = first.operator+(second);

这两种表示法都将调用operator + ()方法。注意,在操作符表示法中,操作符左侧的对象(这里为first)是调用对象,操作符右边的对象(这里为second)是作为参数被传递的对象。

可以将两个以上的对象相加吗?例如,t1、t2、t3都是Time对象,可以这样做吗?

Time t = t1 + t2 + t3;

回答是当然可以,因为函数调用其实是

Time t = t1.operator+(t2.operator+(t3));

重载操作符为全局函数写法

既然重载操作符为全局函数,那么Time.h和Time.cpp的operator+()就可以删掉了,并把minutes_和hours_设置为公有变量(这是因为全局函数没有权限访问类的私有变量),改成:

Time operator+(const Time& t1, const Time& t2)
{
	Time sum;

	sum.minutes_ = t1.minutes_ + t2.minutes_;
	sum.hours_ = t1.hours_ + t2.hours_ + sum.minutes_ / 60;
	sum.minutes_ %= 60;

	return sum;
}

int main()
{
	Time first(1, 20);
	Time second(2, 30);

	std::cout << "第一次花费时间:";
	first.Show();

	std::cout << "第二次花费时间:";
	second.Show();

	// Time total = first.Sum(second);
	Time total = first + second;
	std::cout << "总计花费时间:";
	total.Show();

	system("pause");
	return 0;
}

结果和上面一样。

经过对比,我们发现重载操作符函数里使用了两个Time对象。

所以,对于一元操作符,定义为全局函数时需要一个参数,而定义为成员函数时则没有参数;对于二元操作符,定义为全局函数时需要两个参数,而定义为成员函数时需要一个参数。

为什么定义为成员函数只需要一个参数,因为成员函数可以使用类的this指针,类成员和函数参数,这就是两个参数。

重载操作符和友元的关系

我们发现,将重载操作符设置为全局函数时,在这种情况下对类来说该操作符就是一个外部函数。因此要想在操作符中访问类的private成员,就必须把其定义为所操作类的友元。

class Time
{
public:

	Time();

	Time(int _h, int _m = 0);

	void AddMin(int _m);

	void AddHour(int _h);

	void Reset(int _h = 0, int _m = 0);

	friend Time operator +(const Time& t1, const Time& t2);

	void Show() const;

private:

	int hours_;

	int minutes_;

};

Time operator+(const Time& t1, const Time& t2)
{
	Time sum;

	sum.minutes_ = t1.minutes_ + t2.minutes_;
	sum.hours_ = t1.hours_ + t2.hours_ + sum.minutes_ / 60;
	sum.minutes_ %= 60;

	return sum;
}

int main()
{
	Time first(1, 20);
	Time second(2, 30);

	std::cout << "第一次花费时间:";
	first.Show();

	std::cout << "第二次花费时间:";
	second.Show();

	// Time total = first.Sum(second);
	Time total = first + second;
	std::cout << "总计花费时间:";
	total.Show();

	system("pause");
	return 0;
}

实现方法参照上面

重载限制

1.重载后的操作符必须至少有一个操作数是用户定义的类型,这将防止用户为标准类型重载操作符。因此,不能将减法操作符(-)重载为计算两个double值的和,而不是它们的差。虽然这种限制将对创造性有所影响,但可以确保程序正常运行。

2、使用操作符时不能违反操作符原来的句法规则。例如,不能将求模操作符(%)重载成使用一个操作数:

int x;
Time shiva;
% x;
% shiva;

同样,不能修改操作符的优先级。因此,如果将加号操作符重载成将两个类相加,则新的操作符与原来的加号具有相同的优先级。

3.不能定义新的操作符。例如,不能定义operator**()函数来表示求幂。

4、不能重载以下操作符:

  • sizeof ——sizeof操作符。
  • . ——成员操作符。
  • .* ——成员指针操作符。
  • :: ——作用域解析操作符。
  • ?:——条件操作符。
  • typeid ——一个RTTI操作符。
  • const_cast ——强制类型转换操作符。
  • dynamic_cast ——强制类型转换操作符。
  • reinterpret_cast ——强制类型转换操作符。
  • static_cast ——强制类型转换操作符。

5.大多数操作符都可以通过成员或非成员函数进行重载,但下面的操作符只能通过成员函数进行重载:

  • = ——赋值操作符。
  • () ——函数调用操作符。
  • [] ——下标操作符。
  • -> ——通过指针访问类成员的操作符。

文章来源:https://blog.csdn.net/m0_51415606/article/details/134843654
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。