为创建的一个自定义数据类型进行运算符重载
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类成员):
因此,只要包含这样的头文件,我们就像和其他普通数据类型一样使用有理数类型,通过常见运算符正常进行各种运算,例如:
截图:
对比前面普通的Rational类,这样方便很多。
常见的运算符重载形式:返回类型 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类,这样方便很多。
相关文章推荐
- 一个使用c++在lua中创建自定义数据类型的简易方法
- 一个使用c++在lua中创建自定义数据类型的简易方法
- 利用sqlite创建一个数据user,其含有一张表person,该person表中含有三个列,其中第一字段为主键int类型的,其他两个字段自定义数据类型和名称。
- 定义一个不受计算机字长限制的整数类INT,要求INT与INT以及INT与C++基本数据类型int之间能进行+、-、×、÷和=运算,并且能通过cout输出INT类型的值。(持续添加)
- 直接创建一个DataTable,并为之添加数据(自定义DataTable)
- sql创建自定义数据类型
- Scott Mitchell 的ASP.NET 2.0数据教程之62:创建一个用户自定义的Database-Driven Site Map Provider
- Flex中如何创建一个自定义数据显示Tips的slider控件。鼠标按住滑标察看效果
- 一个自定义数据类型,教你使用索引器
- 直接创建一个DataTable,并为之添加数据(自定义DataTable)
- 创建一个同种类型数据的数组
- 创建一个加密表空间并对表内数据进行加密的示例
- 直接创建一个DataTable,并为之添加数据(自定义DataTable)
- 一个使用泛型堆栈模块创建的两个容纳不同类型数据的实例
- CSS+HTML实例集合三,用户自定义创建表格并删除指定行、列,对表格中的数据进行排序,radio单选摁扭之调查问卷、之选择题
- C# 直接创建一个DataTable,并为之添加数据(自定义DataTable)
- 直接创建一个DataTable,并为之添加数据(自定义DataTable)
- 第2章_基本数据类型和基本操作_编程练习Exercise2.7通过创建窗口进行大小写的切换
- 在Lu中创建自定义数据类型,小矩阵乘效率测试
- oracle创建定时job,job调用存储过程,批量查询,批量修改,自定义数据类型,