运算符重载的两种方式

1 基本概念

基础

  • 运算符时具有特殊名字的函数:由关键字operator和气候定义的运算符共同组成。

  • 可以被重载的运算符

方式

  1. 将运算符重载为类的成员函数
  2. 重载运算符函数,并声明为类的友元

规则

  1. 重载后的运算符必须至少有一个操作数是用户定义的类型,这是为了防止程序员为标准类型重载运算符,可以确保程序正确运行。

  2. 不能修改运算符的优先级,不能违反运算符原本的运算规则。例如在重载加号时,不能提供两个形参(友元除外),例如下面的这种重载方式就是不被允许的;因为加法是一种双目运算符。在重载为类的成员函数后,加法运算的第一项应该是调用函数的一个对象。所以在运算符重载时,参数表中的参数数目应该是重载运算符的操作数减1。

1
Time operator+(const Time &t1,const Time &t2) const;
  1. 不能创造新的运算符,例如不能定义operator**()运算符;
  2. 不能重载以下运算符;
1
2
3
4
5
.:成员运算符
.*:成员指针运算符
:: :作用域运算符
?::条件运算符
siezof:sizeof运算符。
  1. 很多运算符可以通过成员或者非成员函数进行重载,但是以下四种只能通过成员函数进行重载;
1
2
3
4
=:赋值运算符;
( ):函数调用运算符;
[ ]: 下标运算符
->:通过指针方位类成员的运算符。
  1. 自增运算符(++)与自减运算符(–)由于自增和自减运算符是单目运算符,在重载时应该是没有参数的,但是又有前置与后置之分,例如++i与i++。为了隽星区分,C++做了规定;
1
2
Time operator++()      //前置
Time operator++(int) //后置

2 成员函数重载

成员函数重载格式

  • 将操作符重载为成员函数。
  • 此时类的对象作为操作符的第一个操作数。流输入输出运算符无法通过这样的方式重载,因为对象本身应该作为第二个操作数,只能通过友元函数的方式对操作进行重载。
1
2
3
4
5
6
7
class MyString{
public:
// 重载等号运算符
MyString& operator=(const MyString &b);
// 重载+=运算符
MyString& operator+=(const MyString &b);
}

3 友元重载

友元的格式

 C++中友元有三种,分别是友元函数,友元类,友元成员函数,这里介绍的是友元函数。

  1. 创建友元函数的第一步是声明,友元函数的声明放在类的声明中,并且在前面加上friend关键字。例如;
1
friend ostream& operator<<(ostream &os, const Time &t);
  1. 第二步是定义友元,友元可以直接在声明的时候进行定义,即内联的定义。也可以定义在类外,定义在类外时,不需要加类作用域运算符,也不需要有friend关键字。
1
2
3
4
5
6
//友元在类外定义的时候,不需要添加friend;
ostream & operator<<(ostream &os, const Time &t)
{
os << "hours:" << t.hours << " " << "mintues:" << t.mintues << " ";
return os;
}

友元使用

与普通的运算符重载成员函数一样,友元也可以直接调用

1
2
cout<<time1<<time2;//等价于
operator<<(operator<<(cout,time1),time2);

4 实例——MyString的实现

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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/* 
* C++ string 类的实现
* 1. 构造函数和析构函数
* 2. 字符串长度
* 3. 重载=运算符
* 4. 重载+=运算符
* 5. 重载<< >> 运算符
* 6. 重载比较运算符
* 7. 重载[]下标运算符
*/

#include <iostream>
#include <cstring>
using namespace std;

class MyString
{
private:
char * str;
int length;
public:
// 长度
int size ()const {
return length;
};
char* getstr()const{
return str;
}
// 默认构造函数
MyString();
// 字符串构造函数
MyString(const char*);
// 复制构造函数
MyString(const MyString& b);

// 重载等号运算符
MyString& operator=(const MyString &b);
// 重载+=运算符
MyString& operator+=(const MyString &b);
// 重载比较运算符
bool operator<(const MyString &b);
// 重载下标运算符
char& operator[](const int &index) const ;
// 重载输入输出操作
friend ostream& operator<<(ostream& ,const MyString &b);
~MyString();
};

MyString::MyString()
{
str = new char[1];
str[0]='\0';
length = 0;
}

MyString::MyString(const char* b){
if(b){
length = strlen(b);
str = new char[length+1];
strcpy(str,b);
}
else{
MyString();
}
}
MyString::MyString(const MyString&b){
length = b.size();
if(length>0)
str = new char[length+1];
else
MyString();
}

MyString& MyString::operator=(const MyString &b){
if(&b == this){
return *this;
}
delete[] str;
length = b.size();
str = new char[length + 1];
strcpy(str,b.getstr());
return *this;
}

MyString& MyString::operator+=(const MyString&b){
if(b.size()==0){
return *this;
}
char* temp = new char[length+b.length+1];
strcpy(temp,str);
strcat(temp,b.getstr());
delete[] str;
str = temp;
return *this;
}

char& MyString::operator[](const int &index)const {
if(index>length)return str[length];
return str[index];
}

bool MyString::operator<(const MyString &b){
for(int i=0;i<length;i++){
if(i>b.size())return false;
if(b[i]>str[i])return true;
if(b[i]<str[i])return false;
}
return true;
}

MyString::~MyString()
{
delete[] str;
}

// 外部定义一个函数,内部声明为友元
ostream& operator<<(ostream &out,const MyString&b){
out<<b.getstr();
return out;
}


int main()
{
// 测试函数
MyString s1,s2="123",s3,s4="456";
s3=s2;
s1=s2;
s1+=s1;
cout<<s1<<endl;
cout<<s2<<endl;
cout<<s3<<endl;
cout<<(s3<s4)<<endl;
cout<<endl;
return 0;
}

5 实例——complex的实现

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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include <iostream>
using namespace std;
class complex{
public:
complex(double real = 0.0, double imag = 0.0): m_real(real), m_imag(imag){ };
public:
friend complex operator+(const complex & A, const complex & B);
friend complex operator-(const complex & A, const complex & B);
friend complex operator*(const complex & A, const complex & B);
friend complex operator/(const complex & A, const complex & B);
friend istream & operator>>(istream & in, complex & A);
friend ostream & operator<<(ostream & out, complex & A);
private:
double m_real; //实部
double m_imag; //虚部
};
//重载加法运算符
complex operator+(const complex & A, const complex &B){
complex C;
C.m_real = A.m_real + B.m_real;
C.m_imag = A.m_imag + B.m_imag;
return C;
}
//重载减法运算符
complex operator-(const complex & A, const complex &B){
complex C;
C.m_real = A.m_real - B.m_real;
C.m_imag = A.m_imag - B.m_imag;
return C;
}
//重载乘法运算符
complex operator*(const complex & A, const complex &B){
complex C;
C.m_real = A.m_real * B.m_real - A.m_imag * B.m_imag;
C.m_imag = A.m_imag * B.m_real + A.m_real * B.m_imag;
return C;
}
//重载除法运算符
complex operator/(const complex & A, const complex & B){
complex C;
double square = A.m_real * A.m_real + A.m_imag * A.m_imag;
C.m_real = (A.m_real * B.m_real + A.m_imag * B.m_imag)/square;
C.m_imag = (A.m_imag * B.m_real - A.m_real * B.m_imag)/square;
return C;
}
//重载输入运算符
istream & operator>>(istream & in, complex & A){
in >> A.m_real >> A.m_imag;
return in;
}
//重载输出运算符
ostream & operator<<(ostream & out, complex & A){
out << A.m_real <<" + "<< A.m_imag <<" i ";;
return out;
}
int main(){
complex c1, c2, c3;
cin>>c1>>c2;
c3 = c1 + c2;
cout<<"c1 + c2 = "<<c3<<endl;
c3 = c1 - c2;
cout<<"c1 - c2 = "<<c3<<endl;
c3 = c1 * c2;
cout<<"c1 * c2 = "<<c3<<endl;
c3 = c1 / c2;
cout<<"c1 / c2 = "<<c3<<endl;
return 0;
}

6 实例——MyTime的实现

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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
//------mytime.h
#ifndef MYTIME_H
#define MYTIME_H
#include <iostream>

using namespace std;

class Time
{
//----------私有成员,类中的成员默认是私有的
private:
int hours;
int mintues;

//----------共有成员
public:
Time(); //默认构造函数
Time(int h, int m = 0); //显式构造函数
Time(const Time &); //拷贝构造函数
~Time(); //析构函数
void AddMin(int m);
void AddHour(int h);

void reset(int h = 0, int m = 0);

//------展示函数show()
void Time::show() const
{
cout << "hours:" << hours << " " << "mintues:" << mintues << " ";
}



Time operator+(const Time &t) const; //运算符重载

Time operator-(const Time &t) const;
Time operator*(double n) const;
friend Time operator*(double n, const Time &t) //友元;
{
return t*n; //在这里又调用了重载运算符 operator*(double n) const;
} //内联形式的定义;



friend ostream & operator<<(ostream &os, const Time &t); //一个双目运算符在重载时,如果是以友元的形式声明的,那么他有两个形参;如果是类的成员函数,那么他只有一个形参;

};


//-------时间重置,内联函数
inline void Time::reset(int h, int m)
{
hours = h;
mintues = m;
}

#endif


//--mytime.cpp

#include <iostream>
#include "mytime.h"

using namespace std;

//-------默认构造函数
Time::Time()
{
hours = mintues = 0;
cout << "调用默认构造函数" << endl;
}

//------显式的构造函数
Time::Time(int h, int m) :hours(h), mintues(m)
{
cout << "调用显式构造函数" << endl;
}

//------拷贝构造函数
Time::Time(const Time &t)
{
hours = t.hours;
mintues = t.mintues;
cout << "调用拷贝构造函数" << endl;
}

//------析构函数
Time::~Time()
{
cout << "调用了析构函数" << endl;
}

//-------小时相加
void Time::AddHour(int h)
{
hours += h;
}

//------分钟相加
void Time::AddMin(int m)
{
mintues += m;
hours += mintues / 60;
mintues %= 60;
}


//------重载+号
Time Time::operator+(const Time &t) const
{
Time sum;
sum.mintues = mintues + t.mintues;
sum.hours = hours + t.hours + sum.mintues / 60;
sum.mintues = sum.mintues % 60;
return sum;
}

//------重载-号
Time Time::operator-(const Time &t) const
{
Time diff;

int time1 = hours * 60 + mintues;
int time2 = t.hours * 60 + t.mintues;

diff.hours = (time1 - time2) / 60;
diff.mintues = (time1 - time2) % 60;

return diff;
}

//-------重载乘号
Time Time::operator*(double n) const
{
Time result;
long totalMintues = n*hours * 60 + n*mintues;

result.hours = totalMintues / 60;
result.mintues = totalMintues % 60;

return result;
}



//-------友元输出操作符
ostream & operator<<(ostream &os, const Time &t) //友元在类外定义的时候,不需要添加friend;
{
os << "hours:" << t.hours << " " << "mintues:" << t.mintues << " ";
return os;
}

//-----------------------
//main.cpp
//不用先生
//------------------------
#include <iostream>
#include "mytime.h"

using namespace std;


int main()
{

{
Time eat_breakfast(0, 45);
Time eat_lunch(1, 0);
Time eat_dinner(1, 30);



Time swiming(0, 45); //非const对象,既可以调用const成员函数,也可以调用非const成员。
const Time study(8, 5); //const对象只能调用const成员函数。


// study_cut_swim;
Time study_cut_swim = study - swiming; //调用运算符重载后的Time类的减号;


Time Eat_time_day = eat_breakfast + eat_dinner + eat_lunch; //调用了重载以后的加法;

cout << "学习比游泳多花" << study_cut_swim << endl; //调用友元输出运算符<<
cout << "每周吃饭所花费的时间为" << (7 * Eat_time_day) << endl; //调用了友元乘法以及输出运算符;
}



system("pause");
return 0;
}