当调用一个重载函数和重载运算符时,编译器通过把您所使用的参数类型和定义中的参数类型相比较,巨鼎选用最合适的定义。(重载决策)
重载运算符时带有特殊名称的函数,函数名是由关键字operator
和其后要重载的运算符符号构成,与其他函数一样,重载运算符有一个返回类型和一个参数列表。
返回类型 operator 运算符(参数列表)
{...
}
大多数的重载运算符可被定义为不同的非成员函数,或者定义为类成员函数。
不可重载的运算符:
.
成员访问运算符.*
->*
成员指针访问运算符::
域运算符?:
条件运算符#
预处理符号
输入输出运算符重载
首先我们需要对流输入输出的原理有一个简单的理解。
cin
是istream
类的对象,cout
是ostream
类的对象
cin>>x;
相当于cin.operator>>x;
然后会在输入缓冲区中读入整型数据后返回流输入对象cin
,方便以后再次输入。
我们可以传统的写法进行运算符重载:
例如:
#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;}ostream& operator<<(ostream& os){os << "英寸:" << feet << "\n英尺:" << inches;return os;}
};
int main()
{Distance d1(20, 18);d1 << cout << endl<< "成功"<< endl;//相当于d1.operator<<(cout)
}
运行结果:
这样写虽然可以但是不太符合我们的习惯,我们更习惯将cout
放到最左边。为了能够适用这种写法,我们需要使用友元函数。
详见代码:
#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& os,const Distance& x){os << "英寸:" << x.feet << "\n英尺:" << x.inches;return os;}
};
int main()
{Distance d1(20, 18);cout<< d1 << endl<< "成功"<< endl;//相当于d1.operator<<(cout)
}
这样写起来就显得很自然。这里我们通过友元函数进行重载。因为<<是二元操作符的缘故我们需要两个参数。其他操作符也可以使用友元函数进行重载,只需要将操作对象放到参数列表中即可。
自增自减运算符的重载
因为自增自减运算符有前缀和后缀之分,因此在重载时也有所不同。除去实现上的不同,后缀运算符在重载的时候参数列表需要有一个int
,来向编译器说明这是一个后缀形式 。例如:
返回类型 operator++ (int)
{}
自增和自减运算符一般是改变对象的状态,所以一般是重载为成员函数。
在实际实现的时候,对于前缀运算符我们直接改变成员的状态然后返回一个相同的成员。对于后缀运算符我们先创建一个对象保存对象的值,然后进行改变,最后返回原来的值。
例如:
#include <iostream>
using namespace std;class Time
{private:int hours; // 0 到 23int minutes; // 0 到 59public:// 所需的构造函数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; // 对象加 1if(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 加 1T1.displayTime(); // 显示 T1++T1; // T1 再加 1T1.displayTime(); // 显示 T1T2++; // T2 加 1T2.displayTime(); // 显示 T2T2++; // T2 再加 1T2.displayTime(); // 显示 T2return 0;
}
赋值运算符重载
详见实例:
#include <iostream>
using namespace std;class Distance
{private:int feet; // 0 到无穷int inches; // 0 到 12public:// 所需的构造函数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;
}
函数调用运算符()重载
重载函数的参数列表就是()
应该加上的内容
#include <iostream>
using namespace std;class Distance
{private:int feet; // 0 到无穷int inches; // 0 到 12public:// 所需的构造函数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;
}
下标运算符[]重载
同样的,重载函数的参数列表应该和[]
中的内容相同。
类成员访问运算符->重载
成员访问运算符可以被重载,只是比较麻烦。它被定义为为一个类赋予指针行为。
- ->必须是一个成员函数
- 返回类型必须是指针或者类的对象
类成员访问运算符->
通常与指针引用运算符*
结合使用。用于实现“智能指针”的功能。这些指针可以自动执行一些操作,如在删除指针的时候同时析构对象等来防止一些内存泄漏的问题。
想要了解更多可以参见:传送门