目录
重载双目运算符
在重载双目运算符时,不言而喻在函数中应该有两个参数。前面举的例子也都是双目运算符。下面举一个双目运算符的应用:
#include <iostream>
#include <string.h>
using namespace std;
class String{
char *p ;
public:
String(){
p=NULL;
}
String(char *str){
p=str;
}
void display(){
cout<<p;
}
friend bool operator>(String &string1 , String &string2);
friend bool operator<(String &string1 , String &string2);
friend bool operator==(String &string1 , String &string2);
};
bool operator>(String &string1 , String &string2){
if(strcmp(string1.p,string2.p)>0)
return true;
else
return false ;
}
bool operator<(String &string1 , String &string2){
if(strcmp(string1.p,string2.p)<0)
return true;
else
return false ;
}
bool operator==(String &string1 , String &string2){
if(strcmp(string1.p,string2.p)==0)
return true;
else
return false ;
}
void compare(String &string1,String &string2){
if(operator>(string1,string2)==1){
string1.display();cout<<">";string2.display();
}
else if(operator<(string1,string2)==1){
string1.display();cout<<"<";string2.display();
}
else {
//else if(operator==(s1,s2)==1)
string1.display();cout<<"<";string2.display();
}
cout<<endl;
}
注:关于字符串的比较,不是比较的长度,而是比较的时候,从字符串左边字符开始,一次比较一个字符,直接出现差异、或者其中一个串结束为止,即长度不能直接决定大小,字符串的大小是由左边开始最前面的字符决定的。
这个比较方法很有值得借鉴的地方,还设有方便函数 compare ,我自己尝试用其他的方法写了一下,但没有写出来。
重载单目运算符
和双目运算符一样,单目运算符只有一个操作数,所以重载运算符函数只有一个参数,如果运算符重载函数作为成员函数,则还可以省略此参数。
下面是一个自增运算符的例子:模拟秒表
#include <iostream>
using namespace std;
class Time{
int hour;
int min;
int sec;
public:
Time(int h=0,int m=0,int s=0):hour(h),min(m),sec(s){}
void display(){
cout<<hour<<":"<<min<<":"<<sec<<endl;
}
Time operator++();
};
Time Time::operator++(){
if(++sec>=60){ //判断条件仔细思考一下
sec=sec-60;
min++;
if(min>=60){
min-=60;
hour++;
}
return *this; //之前讲的系统提供 this 指针。
}
}
int main(){
Time t(16,59,50);
for(int i=1;i<=12;i++){
++t; //注意是前置自加
t.display();
}
}
有个小问题:如何区别前置自加(减)和后置自加(减)?C++约定,在自加(减)运算符重载时,增加一个 int 型形参,就是后置自加(减)运算符函数。即:
#include <iostream>
using namespace std;
class Time{
int hour;
int min;
int sec;
public:
Time(int h=0,int m=0,int s=0):hour(h),min(m),sec(s){}
void display(){
cout<<hour<<":"<<min<<":"<<sec<<endl;
}
Time operator++(); //前置自加运算符重载
Time operator++(int); //后置自加运算符重载
};
Time Time::operator++(int){
Time temp(*this); //建立临时对象 temp
sec++;
if(sec>=60){
sec-=60;
min++;
if(min>=60){
min-=60;
hour++;
}
}
return temp; //返回的是自加前的对象
//此处返回的*this和temp不一样影响着下面主函数中的 t1 的值
}
Time Time::operator++(){
if(++sec>=60){
sec=sec-60;
min++;
if(min>=60){
min-=60;
hour++;
}
}
return *this;
}
int main(){
Time t(16,59,50);
cout<<"t=";t.display();
++t;
cout<<"++t=";t.display();
Time t1;
t1=t++;
cout<<"t1=";t1.display();
cout<<"t++=";t.display();
}
多的这个 int 型的参数,只是为了与前置自加运算符重载函数有所区别,此外并没有任何作用,在定义函数时也不用使用该参数,故可省写参数名,只需在括号中写 int 即可。编译系统在遇到重载后置自加运算符时,会自动调用此参数。
重载流插入运算符
用户自定义的类型的数据(如类对象)是不能直接用 "<<" 和 ">>" 输入输出的,如果想用它们输入输出自己声明的类型的数据,必须对它们重载。对 "<<" 重载的函数形式如下:
ostream& operator<<(ostream &,自定义类 &);
重载运算符 “<<” 的函数的第一个参数和函数的类型都必须时 ostream &类型(即ostream类对象的引用),第二个参数是要进行输入操作的类。最重要的一点是,重载流插入运算符只能作为友元函数,而不能定义为成员函数。
下面是一个输出复数的例子:
#include <iostream>
using namespace std;
class Complex{
double real;
double imag;
public:
Complex(double r=0,double i=0):real(r),imag(i){}
Complex operator+(Complex a);
friend ostream& operator<<(ostream &,Complex);
};
Complex Complex::operator+(Complex a){
return Complex(real+a.real,imag+a.imag) ;
}
ostream& operator<<(ostream &output,Complex c){
output<<"("<<c.real<<","<<c.imag<<"i)"<<endl;
return output;
}
int main(){
Complex c;
/*Complex c1(1,1),c2(2,2),c3;
c3=c1+c2;*/
cout<<c;
}
可以看到经过重载后,“<<”也可以输出自己定义的类对象,但注意形式: ostream& operator<<(ostream&,Complex); 写的时候很容易就忘了加 & 符号。
对这个程序分析一下:运算符重载函数 “operator <<” 中的形参 output 是 ostream 类对象的引用,形参名 output 是自己任意起的。看到主函数中将对象输出时,由于已将运算符 << 的重载函数声明为 Complex 类的友元函数,那么编译时系统会把 cout << c 解释为 operator << (cout ,c),即以 cout 和 c 作为实参,调用 重载运算符函数 “operator <<” ,调用函数时,形参 output 成为实参 cout 的引用。那么不加 & 引用符号不行吗?因为在C++语言中,我们是用 cout 进行输出的,如果不加引用符号,相当于新开辟了一块空间,而和cout没有一点联系,那又如何进行输出呢,所以引用符号 & 千万不能少。
至于最后的 return output 的作用是为了能连续向输出流插入信息。output 是ostream 类的对象的引用(即实参 cout 的引用,或者说是 cout 的别名),cout 通过传递地址给 output ,使它们二者共享一段存储单元,因此 return output 就是 return cout ,将输出流 cout 的现状返回,即保留输出流的现状。如果有以下输出: cout << c << c1 ;程序先执行 cout<<c ;即 (cout << c )<< c1;而执行(cout<<c)得到的结果就是具有新内容的流对象 cout ,因此 (cout <<c) << c1 相当于 cout(新值) << c1.运算符 “<<” 的左侧是 ostream 类对象 cout ,右侧是 Complex 类对象 c1 ,则再次调用运算符 "<<" 重载函数,接着向输出流插入 c1 的数据。这也是为什么 运算符 “<<” 重载函数的第一个参数和函数的类型都必须是 ostream 类型的引用,即使为了返回 cout 的当前值以便连续输出。
还有一点需要注意,在本程序中,在 Complex 类中定义了运算符 "<<" 重载函数为友元函数,因此只有在输出 Complex 类对象时才能使用重载的运算符,对其他类型的对象是无效的。
重载流提取运算符
重载流提取运算符和前边的重载流插入运算符很相似,不过流插入运算符是为了进行输出,这个函数是为了输入,其重载函数形式如下:
istream& operator>>(istream& , 自定义类名);
同样以一个复数类的输入为例:
#include <iostream>
using namespace std;
class Complex{
double real;
double imag;
public:
// Complex(double r=0,double i=0):real(r),imag(i){}
Complex operator+(Complex );
friend istream& operator>>(istream& ,Complex& );
friend ostream& operator<<(ostream& ,Complex );
};
Complex Complex::operator+(Complex c){
Complex a;
a.real=real+c.real;
a.imag=imag+c.imag;
return a;
}
istream& operator>>(istream& input,Complex& c){
input>>c.real>>c.imag;
return input;
}
ostream& operator<<(ostream& output,Complex c){
output<<"("<<c.real<<"+"<<c.imag<<"i)";
return output;
}
int main(){
// Complex c(1,1);
Complex c,c1,c2;
cin>>c>>c1;
cout<<"c="<<c<<endl;
cout<<"c1="<<c1<<endl;
c2=c+c1;
cout<<c2;
}
同样在执行 cin >> c>>c1 时,调用 “operator >>” 函数,将 cin 的地址传递给 input ,input 就是cin 的引用,最后返回 cin 的新值。用 cin 和 ">>" 可以连续从输入流提取数据给程序中的 Complex 类对象,或者说,用 cin 和 ">>" 可以连续向程序输入 Complex 类对象的值,在主函数中,每遇到一次 “>>” ,就调用一次重载运算符 “>>” 的函数。
该函数可以再完善一下,因为发现如果输入的虚部是负数,结果就不是我们想要的情况。只需要改一下输出部分的代码,即
ostream& operator<<(ostream& output,Complex c){
output<<"("<<c.real;
if(c.imag>=0)
cout<<"+";
cout<<c.imag<<"i)";
return output;
}