CPP-11-使用类

运算符重载

运算符重载是一种形式的 C++ 多态

用户能够定义多个名称相同但特征标(参数列表)不同的函数的。称为函数重载或函数多态,旨在能够用同名的函数来完成相同的基本操作,即使这种操作被用于不同的数据类型

首先实现时间操作

file1: mytime0.h,实现类的声明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#ifndef MYTIME0_H_
#define MYTIME0_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

file2: usetime0.cpp 实现类的成员函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <iostream>
#include "mytime0.h"
using namespace std;

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
{
cout << hours << " hours, " << minutes << " minutes" << endl;
}

file3:usertime0.cpp 使用类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
#include "mytime0.h"
using namespace std;

int main()
{
Time planning;
Time coding(2, 40);
Time fixing(5, 55);
Time total;

cout << "planning time = ";
planning.Show();

cout << "coding time = ";
coding.Show();

cout << "fixing time = ";
fixing.Show();

total = coding.Sum(fixing);
cout << "coding.Sum(fixing) = ";
total.Show();
return 0;
}

编译运行如下

1
2
3
4
5
6
7
8
9
/*
g++ -Wall -Werror -std=c++11 -c src/mytime0.cpp -o build/mytime0.o
g++ -Wall -Werror -std=c++11 -c src/usetime0.cpp -o build/usetime0.o
g++ build/mytime0.o build/usetime0.o -o demo
*/
planning time = 0 hours, 0 minutes
coding time = 2 hours, 40 minutes
fixing time = 5 hours, 55 minutes
coding.Sum(fixing) = 8 hours, 35 minutes

添加一个加法运算符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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 + fixing;
cout << "coding + fixing = ";
total.Show();

运行结果与 sum 函数一样

1
2
coding.Sum(fixing) = 8 hours, 35 minutes
coding + fixing = 8 hours, 35 minutes

对象连续相加也是允许的

1
2
3
4
5
total = coding + fixing + coding + planning;
cout << "all + =";
total.Show();

//输出结果 all + =11 hours, 15 minutes

重载的限制也是有的

  1. 重载后的运算符必须至少有一个操作数是用户定义的类型,将防止用户为标准类型重载运算符
  2. 使用运算符时不能违反运算符原来的句法规则。例如,不能将求模运算符(%)重载成使用一个操作数
  3. 不能创建新运算符。例如,不能定义operator **( )函数来表示求幂
  4. 不能重载下面的运算符
    • sizeof:sizeof运算符
    • .:成员运算符。
    • . *:成员指针运算符。
    • :::作用域解析运算符。
    • ?::条件运算符。
    • typeid:一个RTTI运算符。
    • const_cast:强制类型转换运算符。
    • dynamic_cast:强制类型转换运算符。
    • reinterpret_cast:强制类型转换运算符。
    • static_cast:强制类型转换运算符。

友元

C控制对类对象私有部分的访问。通常,公有类方法提供唯一的访问途径,但是有时候这种限制太严格,C提供了另外一种形式的访问权限:友元

友元有3种:

  • 友元函数
  • 友元类
  • 友元成员函数

为何需要友元?为类重载二元运算符时(带两个参数的运算符)常常需要友元,通过让函数成为类的友元,可以赋予该函数与类的成员函数相同的访问权限

比如Time 类重载操作符号*

1
2
3
4
5
6
7
8
9
10
Time operator+(double n) const;

Time Time::operator+(double n) const
{
Time sum;
sum.minutes = minutes * n % 60;
sum.hours = hours + minutes * n / 60;
sum.hours = sum.hours % 24;
return sum;
}

上述可以 使用 A = B * 0.75 但是无法用来实现 A = 0.75 * B,这样不就和普通的 * 不一样了吗

友元就是为了解决这个问题,步骤如下

  1. 将其原型放在类声明中,并在原型声明前加上关键字 friend
1
2
friend Time operator*(double m, const Time & t); 	//gose in class declaration
//friend Time operator*(double n, const Time & t) const; //x 非成员函数上不允许使用类型限定符
  • 虽然operator *( )函数是在类声明中声明的,但它不是成员函数,因此不能使用成员运算符来调用;
  • 虽然operator *( )函数不是成员函数,但它与成员函数的访问权限相同
  • 注意,不能使用 类型限定符,因为 此时的 opeartor* 不是成员函数
  1. 是编写函数定义。因为它不是成员函数,所以不要使用 Time::限定符。另外,不要在定义中使用关键字friend

    1
    2
    3
    4
    5
    6
    7
    8
    Time operator*(double m, const Time & t)	//friend not used in definition
    {
    Time sum;
    sum.minutes = minutes * m % 60;
    sum.hours = hours + minutes * m / 60;
    sum.hours = sum.hours % 24;
    return sum;
    }

有了上述声明和定义后,就可以使用 A = 2.75 * B

1
2
3
4
5
6
7
8
Time operator*(double m, const Time & t)	//friend not used in definition
{
Time sum;
sum.minutes = t.minutes % 60;
sum.hours = t.hours + t.minutes * m / 60;
sum.hours = sum.hours % 24;
return sum;
}

由于不是成员函数,所以不能直接使用 sum.minutes = minutes % 60;

1
2
total = coding * 0.75;	//错误,没有与这些操作数匹配的 "*" 运算符
total = 0.25 * coding;

所以,上述的友元函数并不能两者都支持,还是需要一个重载的成员函数

参考链接

  1. 《C++ Primer Plus》