还记得
cout
和
cin
吗?
cin>>a;
cout<<a<<endl;
>>
运算符在C语言中是右移运算符,用于整数,表示右移一位,相当于/2,<<
是左移运算符,用于整数,相当于*2;
然而这两个运算符在这里却对输入输出流进行操作,显然已经不是二进制移位运算符了,这就是说,它们被赋予了新的功能.对系统原有的运算符赋予其它功能的过程,称为运算符的重载.
重载的规则
只能对系统已有的运算符进行重载,不能自定义运算符,且除去以下五个运算符不能重载,其余都可以重载:
- 域运算符
::
- 成员访问运算符
.
- 成员指针访问运算符
*
sizeof
运算符- 三目元运算符
? :
重载不改变运算符操作数的个数
重载不改变运算符优先级
重载不改变运算符的结合性
重载运算符的函数不能带有默认参数
重载运算符的操作数至少有一个是自定义类,不能全都是标准类型(int,double等)
=
和&
不必重载,适用于每一个类,但是重载=
在某些情况下相当于重载拷贝构造函数(较冷门)
运算符重载的方法
使用operator
关键字进行运算符重载,其格式一般如下:
返回类型 operator 运算符名称(参数列表) {
实现自定义功能的语句;
}
例如我们对Complex类型进行+
重载声明:
Complex operator+(Complex &a, Complex &b);
重载为成员函数
将运算符重载为成员函数时,可省略一个参数,用this
代替当前对象,如:
#include<iostream>
#include<string>
using namespace std;
//Complex.h;
class Complex {
public:
Complex(double,double);
Complex operator+(Complex&);
void show();
private:
double real;
double imag;
};
//Complex.cpp;
Complex::Complex(double r,double i):real(r),imag(i){}
Complex Complex::operator+(Complex &c){
return Complex(this->real+c.real,this->imag+c.imag);
}
void Complex::show() {
if(imag >= 0)
cout<<real<<"+"<<imag<<"i"<<endl;
else
cout<<real<<imag<<"i"<<endl;
}
//main.cpp;
int main() {
Complex c1(10,18),c2(-2,2);
Complex c3 = c1+c2;
c3.show();
return 0;
}
重载函数调用是隐式调用,c1+c2
相当于c1.operator+(c2)
.
注:省略的参数永远都是运算符左边第一个参数,c1+c2,省略的是c1
重载为友元函数
重载为友元函数时,由于不是类的成员函数,因此无法省略一个参数,如:
//Complex.h;
class Complex {
public:
Complex(double,double);
friend Complex operator+(Complex&,Complex&);
void show();
private:
double real;
double imag;
};
//Complex.cpp;
Complex operator+(Complex &c1,Complex &c2) {
return Complex(c1.real+c2.real,c1.imag+c2.imag);
}
可以看出其实这两种重载区别不大,只是参数的个数上的区别,但很多时候重载为友元运算符比成员运算符更为有效,一般可以采用以下的建议(非硬性规定):
重载方式 | 适用运算符类别 |
---|---|
成员函数 | 单目元运算符 |
友元函数 | 双目元运算符 |
重载单目元运算符
以上说的都是双目元运算符的重载,现在我们来看看对单目元运算符的重载,我们一般使用成员函数重载.
前缀和后缀式的区别
我们知道++i
和i++
的区别,是先自增,再使用还是先使用,再自增.那么在重载运算符的时候,也会遇到这个问题.这就是说,对于一个单目元运算符,我们至少要写两种重载形式——前缀式和后缀式.下面以++
运算符为例,介绍两种声明形式:
前缀式:
类名 类名::operator++();
后缀式:
类名 类名::operator++(int);
注:二者相差一个int
参数是C++所规定的,实际使用并不需要传递参数,编译系统会根据单目元运算符的位置确定调用哪个函数.
下面我们写一个含有hour和minute的Time类,完成对++
和--
的两种形式重载:
#include<iostream>
#include<string>
using namespace std;
//Time.h;
class Time {
public:
Time();
Time(int,int);
Time operator++();
Time operator++(int);
Time operator--();
Time operator--(int);
void show();
private:
int hour;
int minute;
};
//Time.cpp;
Time::Time() {
hour = 0;
minute = 0;
}
Time::Time(int h,int m):hour(h),minute(m){}
Time Time::operator++() {
if(++minute >= 60) {
minute -= 60;
if(++hour >= 24) {
hour -= 24;
}
}
return *this;
}
Time Time::operator++(int) {
Time temp = *this;
if(++minute >= 60) {
minute -= 60;
if(++hour >= 24) {
hour -= 24;
}
}
return temp;
}
Time Time::operator--() {
if(--minute < 0) {
minute = 59;
if(--hour < 0) {
hour = 23;
}
}
return *this;
}
Time Time::operator--(int) {
Time temp = *this;
if(--minute < 0) {
minute = 59;
if(--hour < 0) {
hour = 23;
}
}
return temp;
}
void Time::show() {
cout<<hour<<":"<<minute<<endl;
}
//main.cpp;
int main() {
Time t1(23,59),t2(0,0);
Time tmp = t1++;
Time temp = ++t1;
temp.show();
tmp.show();
temp = t2--;
tmp = --t2;
temp.show();
tmp.show();
return 0;
}
注:C++特别提供了成员函数重载以区分单目元运算符前缀后缀式的方法,请不要再使用友元类重载了!
重载>>
和<<
运算符
在编写程序的过程中,输入和输出总是一件很重要的事情,基于这个原因,我们会想使用cin
和cout
直接输入/输出自定义的类型,但是这两个函数只能识别基本类型,因此我们需要对>>和<<进行重载,以达到使用cin和cout输入/输出自定义类的目的.
只能将>>
和<<
的重载函数作为友元,而不能作为类的成员函数,这是因为,C++对其重载的格式的要求,如下:
istream& operator>>(istream&,自定义类名&);
ostream& operator<<(ostream&,自定义类名&);
注:其中istream
和ostream
分别是输入流和输出流,是标准类库的两个类,用户无法更改.
按照成员函数重载省略左边第一个参数的原则,即使要写成成员函数重载,也只能写成istream
或ostream
的成员函数,这显然是无法做到的,因此只能重载为友元函数.
下面实现一个简单例子:
#include<iostream>
#include<string>
using namespace std;
//Time.h;
class Time {
public:
Time();
friend istream& operator>>(istream&,Time&);
friend ostream& operator<<(ostream&,Time&);
void show();
private:
int hour;
int minute;
};
//Time.cpp;
Time::Time() {
hour = 0;
minute = 0;
}
istream& operator>>(istream &input,Time &t) {
input>>t.hour>>t.minute;
return input;
}
ostream& operator<<(ostream &output,Time &t) {
output<<t.hour<<":"<<t.minute<<endl;
return output;
}
//main.cpp;
int main() {
Time t;
cin>>t;
cout<<t;
return 0;
}
注:请务必按照要求,将>>
和<<
重载为友元运算符.
小结
- 运算符不止可以重载为友元、成员函数,还可以是普通函数
- 对于第一点,由于类的封装性特点,普通函数可能无法访问一些数据成员,因此不常用
- 运算符既可重载为友元函数,也可以重载为成员函数;
- 成员函数少写第一个参数,且该参数必然是本类对象类型;
- 对于重载为友元函数的运算符,建议使用引用;
- 单目元运算符只用成员函数重载
- 双目元运算符建议使用友元函数重载
- 双目元运算符重载函数,并不一定要求两个参数是同一类型
- 对于
>>
和<<
的重载,只能重载为友元函数,且有格式要求
以上就是运算符重载的全部内容