运算符重载将重载的概念扩展到运算符上,允许赋予C++运算符多种含义。实际上,很多C++运算符已经重载。将*运算符用于地址,将得到存储在这个地址中的值;但将它用于两个数字时,得到的将是它们的乘积。C++根据操作数的数目和类型来决定采用哪些操作。
C++允许将运算符重载扩展到用户定义的类型。例如:允许使用+将两个对象相加。编译器将根据操作数的数目和类型决定使用哪个加法定义。
重载运算符让代码看起来更自然。不过重载运算符,需使用被称为运算符函数的特殊函数形式。格式如下:
operatorop(argument-list)
例如:operator+()重载+运算符,operator()重载运算符。op必须是有效的C++运算符,不能虚构一个新的符号。
当然最重要的是,当调用的时候,可以使用简便的运算符表示法,而不必使用笨拙的函数表示法。
我们用示例来讲解下上述内容。
计算时间的示例
假如我上午花费在简书上的时间是2小时8分钟,下午花费在简书的时间是3小时23分钟,则总共花费了多长时间在抖音上呢?我们用程序来表示下。
//
// Created by fukaiqiang on 22-8-13.
//
#ifndef OPERATOR_TIME_H
#define OPERATOR_TIME_H
class Time {
private:
int hours;
int minutes;
public:
Time();
Time(int h,int m = 0);
void AddMin(int m);
void AddHr(int h);
void Reset(int h = 0,int m = 0);
Time Sum(const Time& t) const;
void Show() const;
};
#endif //OPERATOR_TIME_H
Time类提供了用于调整和重新设置时间、显示时间、将两个时间相加的方法。请注意,当总的分钟数超过59时,AddMin()和Sum()方法是如何使用整数除法和求模运算符来调整minutes和hour值的。另外这里只使用了iostream和cout,且只使用了一次,因此使用std::cout比导入整个名称空间更经济。
//
// Created by fukaiqiang on 22-8-13.
//
#include "Time.h"
#include <iostream>
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::AddHr(int h) {
hours += h;
}
void Time::Reset(int h, int m) {
hours = h;
minutes = m;
}
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 << "hours, " << minutes << "minutes";
}
来看下Sum()函数的代码。注意参数是引用,但是返回类型却不是引用。将参数声明为引用的目的是为了提高效率。如果按值传递Time对象,代码的功能将相同,但传递引用,速度将更快,使用的内存将更少。
另外。返回值不能是是引用。因为函数将创建一个新的Time对象sum,来表示另外两个Time对象的和。返回对象将创建对象的副本,而调用函数可以使用它。然后,如果返回类型为Time&,则引用的将是sum对象。但由于sum对象是局部变量,在函数结束时将被删除,因此引用将指向一个不存在的对象。使用返回类型Time意味着程序将在删除sum之前构造它的拷贝,调用函数将得到该拷贝。
警告:不要返回指向局部变量或临时对象的引用。函数执行完毕后,局部变量和临时对象将消失,引用将指向不存在的数据。
#include <iostream>
#include "Time.h"
int main() {
using std::cout;
using std::endl;
Time planning;
Time coding(2,40);
Time fixing(5,55);
Time total;
cout << "planning time = ";
planning.Show();
cout << endl;
cout << "coding time = ";
coding.Show();
cout << endl;
cout << "fixing time = ";
fixing.Show();
cout << endl;
total = coding.Sum(fixing);
cout << "coding.Sum(fixing) = ";
total.Show();
cout << endl;
return 0;
}
planning time = 0hours, 0minutes
coding time = 2hours, 40minutes
fixing time = 5hours, 55minutes
coding.Sum(fixing) = 8hours, 35minutes
为示例添加加法运算符
把Sum替换为operator+,如下所示
Time operator+(const Time& t) const;
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;
}
total = coding.operator+(fixing);
和调用Sum函数一样,operator+也是由Time对象调用,将第二个Time对象作为参数,并返回一个Time对象,因此可以像调用Sum函数一样调用operator+函数。
引入运算符表示法
total = coding.operator+(fixing);
可以表示为
total = coding + fixing;
这种运算符表示法也将调用operator+函数。
注意:
- 在运算符表示法中,运算符左侧的对象是调用对象,运算符右边的对象是作为参数被传递的对象。
- 当调用重载运算符时,编译器通过把所使用的参数类型与定义中的参数类型进行比较,决定选用最合适的定义。选择最合适的重载运算符的过程,称为重载决策。
几种运算符重载
一元运算符 - 负号重载
#include <iostream>
using namespace std;
class Distance
{
...
public:
...
void operator-()
{
feet = -feet;
inches = -inches;
}
};
int main()
{
D1.operator-(); // 取相反数
D2.operator-(); // 取相反数
-D1; // 取相反数
-D2; // 取相反数
...
return 0;
}
二元运算符 + 加号重载
本文的主示例即是重载二元运算符 + 加号的示例。
关系运算符 < 小于号重载
bool operator <(const Distance& d)
{
if(feet < d.feet)
{
return true;
}
if(feet == d.feet && inches < d.inches)
{
return true;
}
return false;
}
if (D1 < D2) {
cout << "D1 is less than D2 " << endl;
} else {
cout << "D2 is less than D1 " << endl;
}
递增递减运算符重载
// 重载前缀递增运算符( ++ )
Check operator ++ ()
{
Check temp;
temp.i = ++i;
return temp;
}
// 重载后缀递增运算符( ++ )
Check operator ++ (int)
{
Check temp;
temp.i = i++;
return temp;
}
obj1 = ++obj;
obj1 = obj++;
递减雷同,就不再赘述。
赋值运算符重载
void operator=(const Distance &D )
{
feet = D.feet;
inches = D.inches;
}
D1 = D2;
下标运算符重载
int& operator[](int i)
{
if( i >= SIZE )
{
cout << "索引超过最大值" <<endl;
// 返回第一个元素
return arr[0];
}
return arr[i];
}
cout << "A[12] 的值为 : " << A[12]<<endl;
类成员访问运算符 -> 重载
类成员访问运算符( -> )可以被重载,但它较为麻烦。它被定义用于为一个类赋予"指针"行为。运算符 -> 必须是一个成员函数。如果使用了 -> 运算符,返回类型必须是指针或者是类的对象。
class Ptr{
//...
X * operator->();
};
类 Ptr 的对象可用于访问类 X 的成员,使用方式与指针的用法十分相似。例如:
void f(Ptr p )
{
p->m = 10 ; // (p.operator->())->m = 10
}
语句 p->m 被解释为 (p.operator->())->m
输入输出运算符
friend ostream &operator<<( ostream &output,
const Distance &D )
{
output << "F : " << D.feet << " I : " << D.inches;
return output;
}
friend istream &operator>>( istream &input, Distance &D )
{
input >> D.feet >> D.inches;
return input;
}
Distance D1(11, 10), D2(5, 11), D3;
cout << "Enter the value of object : " << endl;
cin >> D3;
cout << "First Distance : " << D1 << endl;
cout << "Second Distance :" << D2 << endl;
cout << "Third Distance :" << D3 << endl;
Enter the value of object :
70
10
First Distance : F : 11 I : 10
Second Distance :F : 5 I : 11
Third Distance :F : 70 I : 10
可重载运算符/不可重载运算符
可重载运算符/不可重载运算符参考
https://www.runoob.com/cplusplus/cpp-overloading.html
C++ Primer PLUS (第 6 版)中文版
网友评论