原文地址:http://huqunxing.site/2016/09/08/C++%E9%87%8D%E8%BD%BD%E6%9C%BA%E5%88%B6/
C++ 允许在同一作用域中的某个函数和运算符指定多个定义,分别称为函数重载和运算符重载。本篇博客主要介绍C++中函数重载机制和运算符重载机制。
重载声明是指一个与之前已经在该作用域内声明过的函数或方法具有相同名称的声明,但是它们的参数列表和定义(实现)不相同(即参数个数或参数顺序不同)。
当您调用一个重载函数或重载运算符时,编译器通过把您所使用的参数类型与定义中的参数类型进行比较,决定选用最合适的定义。选择最合适的重载函数或重载运算符的过程,称为重载决策。
函数重载
在同一个作用域内,可以声明几个功能类似的同名函数,但是这些同名函数的形式参数(指参数的个数、类型或者顺序)必须不同,不能仅通过返回类型的不同来重载函数。
示例:同名函数 print() 被用于输出不同的数据类型:
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
|
using
namespace
std;
class printData
{
public:
void print(int i) {
cout <<
"Printing int: " << i <<
endl;
}
void print(double f) {
cout <<
"Printing float: " << f <<
endl;
}
void print(char* c) {
cout <<
"Printing character: " << c <<
endl;
}
};
int main(void)
{
printData pd;
// Call print to print integer
pd.print(
5);
// Call print to print float
pd.print(
500.263);
// Call print to print character
pd.print(
"Hello C++");
return
0;
}
|
当上面的代码被编译和执行时,它会产生下列结果:
1
2
3
|
Printing int: 5
Printing float: 500.263
Printing character: Hello C++
|
运算符重载
您可以重定义或重载大部分 C++ 内置的运算符。这样,您就能使用自定义类型的运算符。重载的运算符是带有特殊名称的函数,函数名是由关键字 operator 和其后要重载的运算符符号(如operator +
)构成的。与其他函数一样,重载运算符有一个返回类型和一个参数列表。
基本格式 : 返回类型 operator 运算符 (参数列表)
可重载的运算符:
|+| -| * |\/ |% |^|
|–|–|–|–|–|–|
|& || |~ |! |, |=|
|< |>| <=| >=| ++| –|
|<<| >>| ==| !=| &&| || |
|+= |-= |/= |%= |^= |&=|
||=| *=| <<=| >>=| [] |()|
|-> |->* |new |new [] |delete |delete []|
不可重载的运算符:::
.*
.
?:
一元运算符重载
一元运算符只对一个数操作。++
,--
,-
(负号),!
(逻辑非)。
注意:对于自增,自减运算符的重载,需要区分前缀操作与后缀操作(后缀重载,参数为int,前缀重载无参数)。
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
|
#include <iostream>
using namespace std;
class Time
{
private:
int hours; // 0 到 23
int minutes; // 0 到 59
public:
// 所需的构造函数
Time(){
hours = 0;
minutes = 0;
}
Time(int h, int m){
hours = h;
minutes = m;
}
// 显示时间的方法
void displayTime()
{
cout << "H: " << hours << " M:" << minutes <<endl;
}
// 重载前缀递增运算符( ++ )
Time operator++ ()
{
++minutes; // 对象加 1
if(minutes >= 60)
{
++hours;
minutes -= 60;
}
return Time(hours, minutes);
}
// 重载后缀递增运算符( ++ )
Time operator++( int )
{
// 保存原始值
Time T(hours, minutes);
// 对象加 1
++minutes;
if(minutes >= 60)
{
++hours;
minutes -= 60;
}
// 返回旧的原始值
return T;
}
};
int main()
{
Time T1(11, 59), T2(10,40);
++T1; // T1 加 1
T1.displayTime(); // 显示 T1
++T1; // T1 再加 1
T1.displayTime(); // 显示 T1
T2++; // T2 加 1
T2.displayTime(); // 显示 T2
T2++; // T2 再加 1
T2.displayTime(); // 显示 T2
return 0;
}
|
示例程序输出结果如下:
1
2
3
4
|
H: 12 M:0
H: 12 M:1
H: 10 M:41
H: 10 M:42
|
二元运算符重载
二元运算符需要两个参数。我们平常使用的加运算符( + )、减运算符( - )、乘运算符( * )和除运算符( / )都属于二元运算符。
示例(重载二元运算符+)
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
|
using
namespace
std;
class Box
{
double length;
// 长度
double breadth;
// 宽度
double height;
// 高度
public:
double getVolume(void)
{
return length * breadth * height;
}
void setLength( double len )
{
length = len;
}
void setBreadth( double bre )
{
breadth = bre;
}
void setHeight( double hei )
{
height = hei;
}
// 重载 + 运算符,用于把两个 Box 对象相加
Box
operator+(
const Box& b)
{
Box box;
box.length =
this->length + b.length;
box.breadth =
this->breadth + b.breadth;
box.height =
this->height + b.height;
return box;
}
};
// 程序的主函数
int main( )
{
Box Box1;
// 声明 Box1,类型为 Box
Box Box2;
// 声明 Box2,类型为 Box
Box Box3;
// 声明 Box3,类型为 Box
double volume =
0.0;
// 把体积存储在该变量中
// Box1 详述
Box1.setLength(
6.0);
Box1.setBreadth(
7.0);
Box1.setHeight(
5.0);
// Box2 详述
Box2.setLength(
12.0);
Box2.setBreadth(
13.0);
Box2.setHeight(
10.0);
// Box1 的体积
volume = Box1.getVolume();
cout <<
"Volume of Box1 : " << volume <<
endl;
// Box2 的体积
volume = Box2.getVolume();
cout <<
"Volume of Box2 : " << volume <<
endl;
// 把两个对象相加,得到 Box3
Box3 = Box1 + Box2;
// Box3 的体积
volume = Box3.getVolume();
cout <<
"Volume of Box3 : " << volume <<
endl;
return
0;
}
|
示例程序输出结果:
1
2
3
|
Volume of Box1 : 210
Volume of Box2 : 1560
Volume of Box3 : 5400
|
关系运算符重载
C++ 语言支持各种关系运算符( < 、 > 、 <= 、 >= 、 == 等等),它们可用于比较 C++ 内置的数据类型。我们可以重载任何一个关系运算符,重载后的关系运算符可用于比较类的对象。
示例:(重载 < 运算符)
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
|
#include <iostream>
using namespace std;
class Distance
{
private:
int feet; // 0 到无穷
int inches; // 0 到 12
public:
// 所需的构造函数
Distance(){
feet = 0;
inches = 0;
}
Distance(int f, int i){
feet = f;
inches = i;
}
// 显示距离的方法
void displayDistance()
{
cout << "F: " << feet << " I:" << inches <<endl;
}
// 重载负运算符( - )
Distance operator- ()
{
feet = -feet;
inches = -inches;
return Distance(feet, inches);
}
// 重载小于运算符( < )
bool operator <(const Distance& d)
{
if(feet < d.feet)
{
return true;
}
if(feet == d.feet && inches < d.inches)
{
return true;
}
return false;
}
};
int main()
{
Distance D1(11, 10), D2(5, 11);
if( D1 < D2 )
{
cout << "D1 is less than D2 " << endl;
}
else
{
cout << "D2 is less than D1 " << endl;
}
return 0;
}
|
示例程序输出结果:
1
|
D2 is less than D1
|
输入输出运算符重载
C++ 能够使用流提取运算符 >>
和流插入运算符 <<
来输入和输出内置的数据类型。您可以重载流提取运算符和流插入运算符来操作对象等用户自定义的数据类型。
注意:我们需要把运算符重载函数声明为类的友元函数,这样我们就能不用创建对象而直接调用函数。
示例:(重载提取运算符 >> 和插入运算符 <<)
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
|
#include <iostream>
using namespace std;
class Distance
{
private:
int feet; // 0 到无穷
int inches; // 0 到 12
public:
// 所需的构造函数
Distance(){
feet = 0;
inches = 0;
}
Distance(int f, int i){
feet = f;
inches = i;
}
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;
}
};
int main()
{
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;
return 0;
}
|
示例程序输出结果:
1
2
3
4
5
6
7
|
$./a.out
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
|
赋值运算符重载
就像其他运算符一样,您可以重载赋值运算符( = ),用于创建一个对象,比如拷贝构造函数。
示例:
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
|
#include <iostream>
using namespace std;
class Distance
{
private:
int feet; // 0 到无穷
int inches; // 0 到 12
public:
// 所需的构造函数
Distance(){
feet = 0;
inches = 0;
}
Distance(int f, int i){
feet = f;
inches = i;
}
void operator=(const Distance &D )
{
feet = D.feet;
inches = D.inches;
}
// 显示距离的方法
void displayDistance()
{
cout << "F: " << feet << " I:" << inches << endl;
}
};
int main()
{
Distance D1(11, 10), D2(5, 11);
cout << "First Distance : ";
D1.displayDistance();
cout << "Second Distance :";
D2.displayDistance();
// 使用赋值运算符
D1 = D2;
cout << "First Distance :";
D1.displayDistance();
return 0;
}
|
示例程序执行结果:
1
2
3
|
First Distance : F: 11 I:10
Second Distance :F: 5 I:11
First Distance :F: 5 I:11
|
函数调用运算符()重载
函数调用运算符 () 可以被重载用于类的对象。当重载 () 时,您不是创造了一种新的调用函数的方式,相反地,这是创建一个可以传递任意数目参数的运算符函数。
示例:
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>
using namespace std;
class Distance
{
private:
int feet; // 0 到无穷
int inches; // 0 到 12
public:
// 所需的构造函数
Distance(){
feet = 0;
inches = 0;
}
Distance(int f, int i){
feet = f;
inches = i;
}
// 重载函数调用运算符
Distance operator()(int a, int b, int c)
{
Distance D;
// 进行随机计算
D.feet = a + c + 10;
D.inches = b + c + 100 ;
return D;
}
// 显示距离的方法
void displayDistance()
{
cout << "F: " << feet << " I:" << inches << endl;
}
};
int main()
{
Distance D1(11, 10), D2;
cout << "First Distance : ";
D1.displayDistance();
D2 = D1(10, 10, 10); // invoke operator()
cout << "Second Distance :";
D2.displayDistance();
return 0;
}
|
示例程序执行结果:
1
2
|
First Distance : F: 11 I:10
Second Distance :F: 30 I:120
|
下标运算符[]重载
下标操作符 [] 通常用于访问数组元素。重载该运算符用于增强操作 C++ 数组的功能。
示例:
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
|
#include <iostream>
using namespace std;
const int SIZE = 10;
class safearay
{
private:
int arr[SIZE];
public:
safearay()
{
register int i;
for(i = 0; i < SIZE; i++)
{
arr[i] = i;
}
}
int& operator[](int i)
{
if( i > SIZE )
{
cout << "索引超过最大值" <<endl;
// 返回第一个元素
return arr[0];
}
return arr[i];
}
};
int main()
{
safearay A;
cout << "A[2] 的值为 : " << A[2] <<endl;
cout << "A[5] 的值为 : " << A[5]<<endl;
cout << "A[12] 的值为 : " << A[12]<<endl;
return 0;
}
|
示例程序执行结果:
1
2
3
4
5
6
|
$ g++ -o test test.cpp
$ ./test
A[2] 的值为 : 2
A[5] 的值为 : 5
A[12] 的值为 : 索引超过最大值
0
|
类成员访问运算符->重载
类成员访问运算符( -> )可以被重载,但它较为麻烦。它被定义用于为一个类赋予”指针”行为。运算符 -> 必须是一个成员函数。如果使用了 -> 运算符,返回类型必须是指针或者是类的对象。
运算符 -> 通常与指针引用运算符 * 结合使用,用于实现”智能指针”的功能。这些指针是行为与正常指针相似的对象,唯一不同的是,当您通过指针访问对象时,它们会执行其他的任务。比如,当指针销毁时,或者当指针指向另一个对象时,会自动删除对象。
间接引用运算符 -> 可被定义为一个一元后缀运算符。也就是说,给出一个类:
1
2
3
4
|
class Ptr{
//...
X * operator->();
};
|
类 Ptr 的对象可用于访问类 X 的成员,使用方式与指针的用法十分相似。例如:
1
2
3
4
|
void f(Ptr p )
{
p->m = 10 ; // (p.operator->())->m = 10
}
|
语句 p->m
被解释为 (p.operator->())->m
。
示例:
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
|
using
namespace
std;
// 假设一个实际的类
class Obj {
static
int i, j;
public:
void f() const {
cout << i++ <<
endl; }
void g() const {
cout << j++ <<
endl; }
};
// 静态成员定义
int Obj::i =
10;
int Obj::j =
12;
// 为上面的类实现一个容器
class ObjContainer {
vector<Obj*> a;
public:
void add(Obj* obj)
{
a.push_back(obj);
// 调用向量的标准方法
}
friend
class SmartPointer;
};
// 实现智能指针,用于访问类 Obj 的成员
class SmartPointer {
ObjContainer oc;
int index;
public:
SmartPointer(ObjContainer& objc)
{
oc = objc;
index =
0;
}
// 返回值表示列表结束
bool
operator++()
// 前缀版本
{
if(index >= oc.a.size())
return
false;
if(oc.a[++index] ==
0)
return
false;
return
true;
}
bool
operator++(
int)
// 后缀版本
{
return
operator++();
}
// 重载运算符 ->
Obj*
operator->()
const
{
if(!oc.a[index])
{
cout <<
"Zero value";
return (Obj*)
0;
}
return oc.a[index];
}
};
int main() {
const
int sz =
10;
Obj o[sz];
ObjContainer oc;
for(
int i =
0; i < sz; i++)
{
oc.add(&o[i]);
}
SmartPointer sp(oc);
// 创建一个迭代器
do {
|