# 十.运算符重载
将系统自定义的运算符用于用户自定义的类型,运算符重载的实质是函数重载
格式:返回类型 operator <符号> (参数表)
{ 重载函数体 }
不能重载的运算符:
成员访问运算符 | 成员指针运算符 | 域操作运算符 | 条件运算符 | 空间计算运算符 |
---|---|---|---|---|
. | ***** | : : | ? : | sizeof |
注意:
- 不允许定义新的运算符
- 不能改变该运算符操作数(对象)的个数
- 不能改变该运算符的优先级别和结合性
- 应该符合实际需要,重载的功能应该与运算符原有的功能相似,避免没有目的的使用重载运算符
对于同一个重载函数,要么定义为成员函数,要么定义为友元函数,不能二者都定义,否则容易引起二义性
# 1. 运算符重载为友元函数
声明格式:friend 返回类型 operator 运算符(参数表);
函数定义:返回类型 operator 运算符(参数表)
{ 函数体 }
如:
#include<iostream>
using namespace std;
class Complex
{
private:
double real,image;
public:
Complex(double r,double i):real(r),image(i){}
void show() //输出虚数的函数
{
if(image > 0)
{
if(image == 1)
cout<<real<<"+"<<"i"<<endl;
else
cout<<real<<"+"<<image<<"i"<<endl;
}
else if(image < 0)
{
if(image == -1)
cout<<real<<"-"<<"i"<<endl;
else
cout<<real<<image<<"i"<<endl;
}
else
cout<<real<<endl;
}
friend Complex operator+(const Complex &c1,const Complex &c2);//声明友元函数
friend bool operator==(const Complex &c1,const Complex &c2);
};
Complex operator+(const Complex &c1,const Complex &c2) //重载+运算符
{
Complex t;
t.real = c1.real + c2.real;
t.image = c1.image + c2.image;
return t; //返回类对象
}
bool operator==(const Complex &c1,const Complex &c2) //重载==运算符
{
if(c1.real == c2.real && c1.image == c2.image)
return true;
else
return false;
}
int main()
{
Complex c1(1,1),c2(2,2);
c1.show();
c2.show();
Complex c3 = c1 + c2; //隐式调用
//Complex c3 = operator+(c1,c2); //显式调用
if(c1 == c2) //调用==重载函数
cout<<"两个复数相等"<<endl;
else
cout<<"两个复数不相等"<<endl;
}
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
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
# 2. 运算符重载为成员函数
如果是重载为双目运算符,就只要设置一个参数作为右侧运算量,而左侧运算量就是该对象本身
如果是重载单目运算符,就不必另外设置参数,运算符的操作量就是对象本身
函数定义:
返回类型 operator 运算符(参数表)
{ 函数体 }
#include<iostream>
using namespace std;
class Complex
{
private:
double real,image;
public:
Complex(double r,double i):real(r),image(i){}
void show() //输出虚数的函数
{
if(image > 0)
{
if(image == 1)
cout<<real<<"+"<<"i"<<endl;
else
cout<<real<<"+"<<image<<"i"<<endl;
}
else if(image < 0)
{
if(image == -1)
cout<<real<<"-"<<"i"<<endl;
else
cout<<real<<image<<"i"<<endl;
}
else
cout<<real<<endl;
}
Complex operator+(const Complex &c1) //重载+运算符函数,只有一个参数
{
Complex t;
t.real = this->real + c1.real;
t.image = this->image + c1.image;
return t;
}
Complex operator==(const Complex &c1) //重载==运算符函数
{
if(this->real == c1.real && this->image == c1.image)
return true;
else
return false;
}
};
int main()
{
Complex c1(1,1),c2(2,2);
c1.show();
c2.show();
Complex c3 = c1 + c2; //隐式调用
//Complex c3 = operator+(c1,c2); //显式调用
if(c1 == c2) //调用==重载函数
cout<<"两个复数相等"<<endl;
else
cout<<"两个复数不相等"<<endl;
}
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
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
# 3. 几种常用的运算符重载
# (1)输入>>和输出<<运算符
只能采用友元形式
格式:ostream &operator<<( ostream &, const 类对象引用);
//ostream &的作用是可以实现连续输出,参数中ostream的引用不能用const修饰,因为向流中写入数据会改变流的状态
istream &operator>>( istream &, 类对象引用);
#include<iostream>
using namespace std;
class Complex
{
... // 内容省略
friend ostream &operator<<(ostream &myout,const Complex &c);//声明输出重载函数
friend istream &operator>>( istream &myin,Complex &c);//声明输入重载函数
};
ostream &operator<<(ostream &myout,const Complex &c)//定义输出运算符重载函数
{
if(c.image > 0)
{
if(c.image == 1)
cout<<c.real<<"+"<<"i"<<endl;
else
cout<<c.real<<"+"<<c.image<<"i"<<endl;
}
else if(c.image < 0)
{
if(c.image == -1)
cout<<c.real<<"-"<<"i"<<endl;
else
cout<<c.real<<c.image<<"i"<<endl;
}
else
cout<<c.real<<endl;
return myout; //返回ostream的引用
}
istream &operator>>( istream &myin,Complex &c)//定义输入运算符重载函数
{
cin>>c.real>>c.image;
return myin; //返回istream的引用
}
int main()
{
Complex c1,c2;
...
//cin.operator>>c1>>c2; //显式调用
cin>>c1>>c2;
cout<<c1<<c2;//若没有定义输出重载函数,则错误,不能输出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
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
# (2)自增运算符++(前置和后置)
后置参数表有一个int型参数,但是前置没有;后置会在函数体里定义一个临时类对象,返回的是临时类对象;前置返回的是当前对象
自减运算符一样
#include<iostream>
using namespace std;
class Complex
{
...
Complex operator++() //定义前置++重载
{
this->real++;
this->image++;
return *this;
}
Complex operator++(int) //定义后置++重载
{
Complex temp = *this;
this->real++;
this->image++;
return temp;
}
};
int main()
{
Complex c1,c2;
...
//Complex c4 = c1.operator++(); //显式调用
Complex c4 = ++c1; //隐式调用
Complex c5 = c1++;
...
return 0;
}
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
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
# (3)赋值操作符=
赋值运算符“=”是双目运算符
如果不定义自己的赋值运算符函数,那么编译器会自动生成一个默认的赋值运算符函数
赋值运算符函数必须是类的成员函数,不允许重载为友元函数
赋值运算符函数不能被派生类继承
与上面赋值运算符函数类似
例1:
#include<iostream> using namespace std; class Complex { ... /*void operator=(const Complex &c) //类型不能为void,因为如果是c1=c2=c3;那么c2=c3返回void,c1不能等于void,所以应为Complex类 { this->real = c.real; this->image = c.image; }*/ Complex operator=(const Complex &c) { this->real = c.real; this->image = c.image; return *this; //系统可以自己写(自带),返回this指针 } }; int main() { Complex c1,c2; ... c1 = c2 = c3;//都为c3的值 ... return 0; }
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例2:
#include<iostream> #include<string> using namespace std; class String { char *sbuf; //用来存放字符串指针 int length; //表示字符串长度 public: String() //不带参数的构造函数,创建一个空串 { length = 0; sbuf = new char; sbuf[0] = '\0'; } String(char *s) //用字符串初始化,串拷贝 { length = strlen(s); sbuf = new char[length + 1]; //开辟空间,对一个空间放'\0'字符串的结束符 strcpy(sbuf,s); } ~String() { delete[] sbuf; //回收空间 } void show() //输出字符串 { cout<<sbuf<<endl; } String(const String &temp) //拷贝构造函数 //深拷贝 { length = temp.length; sbuf = new char[length + 1]; strcpy(sbuf,temp.sbuf); } String& operator=(const String &s) //第一个&的作用是返回当前对象时不会调用拷贝构造函数,防止函数调用开销过大 { if(this == &s) //防止自赋值(如s1 = s1;) return *this; length = s.length; //sbuf = s.sbuf; //不能直接赋值,因为当前对象是先创建再赋值的,创建时已经申请了一个空间,若现在直接赋值,则当前的sbuf指向被复制的sbuf的空间,那么先前的sbuf无指针指向,而被复制的空间有两个指针指向,在析构时会出现错误 delete []sbuf; //要先删除当前对象的sbuf的空间 sbuf = new char[length + 1];//再申请与被复制空间等大的空间,使当前的sbuf等于它 strcpy(sbuf,s.sbuf);//再拷贝字符串 return *this; //返回当前对象 } }; int main() { String s1("Hello");//调用String(char *s); String s2 = s1; //调用String(const String &temp); String s3; //调用String(); s3 = s1; //重点 //调用赋值运算符函数String& operator=(const String &s); s3 = s2 = s1;//连续赋值 //调用String& operator=(const String &s); s1.show(); s2.show(); s3.show(); return 0; }
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