您的位置:首页 > 其它

为创建的一个自定义数据类型进行运算符重载

2015-04-12 18:35 686 查看
在前面一篇文章里谈到编程语言里面只有Int,float,double等基本数据类型,而没有有理数类型,因此我们自定义了一个Rational类型(见http://blog.csdn.net/yanerhao/article/details/45009283),表示有理数,含有四则运算,比较,输出结果等成员函数,但是与常见的基本类型相比,还是显得特殊,显得格格不入。需要进一步基本化,这就是需要运算符重载。运算符重载是自定义新类过程里很重要的一步。在这里以有理数类Rational为例对关系运算符,算术,一元运算符,++,--,[],以及用<<,>>直接代替tostring()成员函数,对象类型转换等运算符进行了重载:

常见的运算符重载形式:返回类型 operator运算符(参数)但是有几点需要注意:

1:一元运算符重载,只是作用于调用本身,所以无参数。

2:[]运算符重载,返回类型 operator[](const int x);可以直接当访问器获得Rational类数据,但是要作为更改器时,需要重新声明:返回类型 & operator[](const int x);

3:++,--运算符重载,分为前缀prefix (先加减再计算)和后缀 postfix(先计算再加减),,如何区分:C++规定:

返回类型operator ++() 为前缀;

返回类型operator ++(int x) 参数有一个伪参为后缀。

4:<<,>>运算符重载,在基本的Rational类,是采用tostring()函数返回有理数,为了达到与Int类型一样直接实现cout<<的效果,我们需要对<<,>>重载。但是于其他运算符重载不同,由于cout,cin是ostream(istream)类的实例,故是对ostream(istream)类内的运算符重载,而只是调用了Rational类的私有数据,很明显符合友元函数特性:

故在Rational类定义友元函数friend ostream&operator <<(ostream&out,Rational &r);friend istream&operator <<(istream&in,Rational &r);

5:对象类型转化。例如需要将有理数转化成double类 operator double(),注意这里没有返回值!C++中这是一种用来定义类型转化函数的特殊语法,函数没有返回类型,函数名就是所期望的目标类型。

新定义的Rational类(包含基本Rational类成员):

int gys(int x,int y){
x=abs(x);
y=abs(y);
int t=1;
int f=1;
while(t<=x&&t<=y){
int re1=x%t;
int re2=y%t;
if(re1==0&&re2==0) f=t;
t++;}
return f;}
int gbs(int x,int y){
x=abs(x);
y=abs(y);
int f=1;
int t=x*y;
while(t>=x&&t>=y){
int re1=t%x;
int re2=t%y;
if(re1==0&&re2==0) f=t;
t--;}
return f;}
class Rational{
private:
long nume;
long deno;
public:
Rational(){nume=0;deno=1;}
Rational(long nume,long b){this->nume=nume;deno=b;}
long getnume(){return nume;}
long getdeno(){return deno;}
Rational getadd(Rational &s){
int deno1=gbs(deno,s.getdeno());
int fnume1=deno1/deno;
int fnume2=deno1/s.getdeno();
int nume1=fnume1*nume+fnume2*s.getnume();
int gbs=gys(deno1,nume1);
int nume2=nume1/gbs;
int deno2=deno1/gbs;
Rational add(nume2,deno2);
return add;}//有理数加法,按照四则运算分数相加法则
Rational getsub(Rational &s){
int deno1=gbs(deno,s.getdeno());
int fnume1=deno1/deno;
int fnume2=deno1/s.getdeno();
int nume1=fnume1*nume-fnume2*s.getnume();
int gbs=gys(deno1,nume1);
int nume2=nume1/gbs;
int deno2=deno1/gbs;
Rational sub(nume2,deno2);
return sub;}//有理数减法,按照四则运算分数相减法则
Rational getmin(Rational &s){
int nume1=nume*s.getnume();
int deno1=deno*s.getdeno();
int gys1=gys(nume1,deno1);
int nume2=nume1/gys1;
int deno2=deno1/gys1;
Rational sub(nume2,deno2);
return sub;}//有理数乘法,直接对应相乘,然后化简
Rational getdiv(Rational &s){
int snume=s.getdeno();
int sdeno=s.getnume();
Rational s1(snume,sdeno);
return getmin(s1);}//有理数除法,除数倒置以后的乘法
int com( Rational &s){
int deno1=gbs(deno,s.getdeno());
int fnume1=deno1/deno;
int fnume2=deno1/s.getdeno();
int nume1=fnume1*nume;
int nume2=fnume2*s.getnume();
if(nume1>nume2) return 1;
else if(nume1==nume2) return 0;
else return -2;}//有理数比较,先雷同有理数加减,化成分母相同,直接比较分子即可

bool equ(Rational &s){
if(com(s)==0) return true;
else return false;}//直接利用已有的比较函数
int intval(){
return nume/deno;}
double doubleval(){
return 1.0*nume/deno;}
string tostring(){
char *str=new char[22];
char *str1=new char[22];
if(deno==1)  {itoa(nume,str,10);return str;}
else {itoa(nume,str,10);itoa(deno,str1,10);
string s1(str);
string s2(str1);
s1.append(1,'/');
s1.append(s2);
return s1;}}//涉及到数和字符串转换itoa(),涉及到字符串到string 转换
//上面是普通的Rational类含有的函数成员
//为了使有理数类像Int类一样具有更多普适性,引入了运算符重载,下面就是:
//Define function operators for relational operators:
bool operator<(Rational &s);
bool operator<=(Rational &s);
bool operator>(Rational &s);
bool operator>=(Rational &s);
bool operator==(Rational &s);
bool operator!=(Rational &s);
//Define functions operators foe arithmetic operators
Rational operator+(Rational&s);
Rational operator-(Rational&s);
Rational operator*(Rational&s);
Rational operator/(Rational&s);
//Define functions operators for shorthand operators
Rational operator+=(Rational&s);
Rational operator-=(Rational&s);
Rational operator*=(Rational&s);
Rational operator/=(Rational&s);
//Define functionp[]
long & operator[](const int&x);
//Define function operator for prefix++ and --
Rational operator++();
Rational operator--();
//Define function operator for postfix++ and --
Rational operator++(int x);
Rational operator--(int x);
//Define function operators for unary + and -
Rational operator+();
Rational operator-();//一元运算符重载,直接作用于对象本身,故无参
//Define function operators for << and >>
friend ostream&operator<<(ostream &out,Rational &r);
friend istream&operator>>(istream&in,Rational &r);
//Define function operators for double
operator double();
//end of operators
private:
long gcd(long x,long y){
x=abs(x);
y=abs(y);
long t=1;
long f=1;
while(t<=x&&t<=y){
int re1=x%t;
int re2=y%t;
if(re1==0&&re2==0) f=t;
t++;}
return f;}
};

bool Rational::operator<(Rational &s){
if(this->com(s)<0) return true;
else return false;}//overload <
bool Rational::operator<=(Rational &s){
if(this->com(s)<0||this->com(s)==0) return true;
else return false;}//overload <=
bool Rational::operator>(Rational &s){
if(this->com(s)>0) return true;
else return false;}//overload >
bool Rational::operator>=(Rational &s){
if(this->com(s)>0||this->com(s)==0) return true;
else return false;}//overload >=
bool Rational::operator==(Rational &s){
if(this->com(s)==0) return true;
else return false;}//overload ==
bool Rational::operator!=(Rational &s){
if(this->com(s)<0||this->com(s)>0) return true;
else return false;}//overload !=
//relational operators
Rational Rational::operator+(Rational &s){
return this->getadd(s);}//overload +
Rational Rational::operator-(Rational &s){
return this->getsub(s);}//overload -
Rational Rational::operator*(Rational &s){
return this->getmin(s);}//overload *
Rational Rational::operator/(Rational &s){
return this->getdiv(s);}//overload /
//arithmetic operators
Rational Rational::operator+=(Rational &s){
*this=this->getadd(s);
return (*this);}//overload +=
Rational Rational::operator-=(Rational &s){
*this=this->getsub(s);
return (*this);}//overload -=
Rational Rational::operator*=(Rational&s){
*this=this->getmin(s);
return (*this);}//overload *=
Rational Rational::operator/=(Rational &s){
*this=this->getdiv(s);
return (*this);}//overload /=
//shorthand operators
long & Rational::operator[](const int&x){
if(x==0) return nume;
else if(x==1) return deno;
else {cout<<"subscript error!"<<endl;
exit(0);}
}//返回引用,那么可以对其赋值如r[0]=1
//overload []
Rational Rational::operator++(){
nume+=deno;
return (*this);}//overload ++,前缀
Rational Rational::operator--(){
nume-=deno;
return (*this);}//overload --,前缀
Rational Rational::operator++(int x){
Rational temp=(*this);
nume+=deno;
return temp;}//overload ++,后缀
Rational Rational::operator--(int x){
Rational temp=(*this);
nume-=deno;
return temp;}//overload --,后缀
//++,--
Rational Rational::operator+(){
return (*this);}
Rational Rational::operator-(){
this->deno=-1*deno;
//this->nume=-1*nume;
return (*this);}//overload -,negetive
//+,-
ostream&operator<<(ostream &out,Rational &r){
out<<r.nume<<"/"<<r.deno<<endl;
return out;}//<<涉及的是ofstream类运算符重载,Rational类只提供数据
istream&operator>>(istream&in,Rational &r){
cout<<"enter the nuem:";
in>>r.nume;
cout<<"enter the deno:";
in>>r.deno;
return in;}//<<涉及的是ifstream类运算符重载,Rational类只提供数据
//<<,>>
Rational::operator double()
{return doubleval();}//对象类型转换,注意不必对需要转换的类型再次返回


因此,只要包含这样的头文件,我们就像和其他普通数据类型一样使用有理数类型,通过常见运算符正常进行各种运算,例如:

int main(){
Rational r1(4,2);
Rational r2(2,3);
//test the relational operators
cout<<"r1>r2 "<<(r1>r2)<<endl;
cout<<"r1<r2 "<<(r1<r2)<<endl;
cout<<"r1==r2 "<<(r1==r2)<<endl;
cout<<"r1!=r2 "<<(r1!=r2)<<endl;
//test tostring ,arithmetic operator
cout<<"r1+r2="<<r1+r2<<endl;//由于重载了<<,所以无需tostring函数
cout<<"r1-r2="<<r1-r2<<endl;
cout<<"r1*r2="<<r1*r2<<endl;
cout<<"r1/r2="<<r1/r2<<endl;
//test shorthand operator
Rational r3(1,2);
r3+=r1;
cout<<"r3: "<<r3<<endl;//由于重载了<<,所以无需tostring函数
//test operator[]
Rational r4(1,2);
r4[0]=3;
r4[1]=4;
cout<<"r4:"<<r4<<endl;//由于重载了<<,所以无需tostring函数
//test operator for ++,--
r3=r4++;
cout<<"r3: "<<r3<<" r4: "<<r4<<endl;
//test double
cout<<"1+ r4="<<(1+r4)<<endl;
system("pause");
return 0;}


截图:



对比前面普通的Rational类,这样方便很多。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐