C++_Primer_Plus之操作符重载
介绍重载操作符
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.大多数操作符都可以通过成员或非成员函数进行重载,但下面的操作符只能通过成员函数进行重载:
- = ——赋值操作符。
- () ——函数调用操作符。
- [] ——下标操作符。
- -> ——通过指针访问类成员的操作符。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!