C++ 面向对象- -运算符的重载(二)

目录

重载双目运算符

重载单目运算符

重载流插入运算符

重载流提取运算符


重载双目运算符

在重载双目运算符时,不言而喻在函数中应该有两个参数。前面举的例子也都是双目运算符。下面举一个双目运算符的应用:

#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;
}

猜你喜欢

转载自blog.csdn.net/qq_43305922/article/details/85457146
今日推荐