运算符重载及流类库课件_第1页
运算符重载及流类库课件_第2页
运算符重载及流类库课件_第3页
运算符重载及流类库课件_第4页
运算符重载及流类库课件_第5页
已阅读5页,还剩91页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第七章运算符重载及流类库运算符重载类运算符和友元运算符++和--运算符的重载流类库运算符“<<”和“>>”的重载格式控制文件操作方式流的错误处理第七章运算符重载及流类库运算符重载运算符重载对基本数据类型,“+”、“–”等,C++用一种简洁的方式工作。例:intx,y,z;z=x+y;若有复数类complex:classcomplex{public:doublereal,imag;complex(doubler=0,doublei=0){real=r;imag=i;}};complexc1(1.1,2.3),c2(2.2,1.3),total;total=c1+c2;运算符重载对基本数据类型,“+”、“–”等,C++用一种运算符重载运算符重载通过创建operator()和一个运算符连用构成运算符函数实现格式:Typeoperator@(参数表){…//(函数定义)}例:intoperator+(x,y){…}返回值type不能是void@表示要重载的运算符,编译时首先检查传递给函数的参数类型,如果看到是自定义的类型,则执行用户自己的函数运算符重载运算符重载通过创建operator()和一个运算符运算符重载complexoperator+(complexom1,complexom2){complextemp;temp.real=om1.real+om2.real;temp.imag=om1.imag+om2.imag;returntemp;}total=c1+c2;(total=operator+(c1,c2);)运算符重载complexoperator+(comple运算符重载说明:只能重载C++语言中原先已有定义的运算符不能重载:..*::?:#不能改变运算符的操作数个数不能改变原有的优先级x=y-a*b;不能改变原有的结合性x=a/b*c;不能改变运算符对预定义类型数据的操作方式+:为加法运算,无法重载而改变它对预定义类型数据的操作方式

重载运算符时至少有一个自定义类型的数据作为操作数运算符重载说明:类运算符成员运算符函数定义的语法形式:classX{…typeoperator@(参数表);…};说明:重载单目运算符,则参数表为空;若运算符为双目运算符,则参数表中有一个操作数。双目运算符重载:classX{…intoperator+(Xa);…};说明:参数作为运算符的右操作数。当前对象作为运算符的左操作数,通过this指针隐含地传递给函数类运算符成员运算符函数定义的语法形式:classcomplex{public:doublereal,imag;complex(doubler=0,doublei=0){real=r;imag=i;}};complexoperator+(complexc){complextemp;temp.real=c.real+real;temp.imag=c.imag+imag;returntemp;}};voidmain(){complexA1(2.3,4.6),A2(3.6,2.8),A3;A3=A1+A2;(解释为:A3=A1.operator+(A2);)}采用成员函数重载双目运算符后,使用的方法:aa@bb;aa.operator@(bb);类运算符双目运算符classcomplex{采用成员函数重载双目运算符后,使类运算符单目运算符单目运算符重载:参数通过this指针隐含地传递给函数classc{intx,y;public:c(inti=0,intj=0){x=i;y=j;}coperator++(){++x;++y;return*this;}};voidmain(){cob(10,20);++ob;ob.operator++();};采用成员函数重载单目运算符后,使用的方法:@aa;aa.operator@();类运算符单目运算符单目运算符重载:classc{采用成员函双目运算符可以被重载为成员函数,但有一种情况:例:成员运算符函数重载了+运算符ob=ob+100解释为ob.operator+(100)但:ob=100+ob;解释为100.operator+(ob)错误类运算符双目运算符可以被重载为成员函数,但有一种情况:类运算符友元运算符友元运算符函数定义的语法形式:friendtypeoperator@(参数表);说明:友元函数没有this指针,若重载的是双目运算符,则参数表中有两个操作数;若重载的是单目运算符,则参数表中有一个操作数友元运算符友元运算符函数定义的语法形式:友元运算符双目运算符classcomplex{public:doublereal,imag;complex(doubler=0,doublei=0){real=r;imag=i;}friendcomplexoperator+(complexa,complexb){complextemp;temp.real=a.real+b.real;temp.imag=a.imag+b.imag;returntemp;}};voidmain(){complexA1(2.3,4.6),A2(3.6,2.8),A3;A3=A1+A2;}采用友元函数重载双目运算符后,使用的方法:aa@bb;operator@(aa,bb);友元运算符双目运算符classcomplex{采用友元函数友元运算符单目运算符classc{intx,y;public:c(inti=0,intj=0){x=i;y=j;}voidshow(){cout<<x<<y;}

//operatorint(){returnx;}friendcoperator++(cop){++op.x;++op.y;

returnop;}};voidmain(){cob(10,20);ob.show();++ob;//cout<<operator++(ob);ob.show();数据成员没有自增?采用友元函数重载单目运算符后,使用的方法:采用引用参数传递操作数,以改变操作数的值operator++(c&op)@aa;operator@(aa);不能用友元函数重载:=()[]->不要改变操作数时,可采用传值的方法。友元运算符单目运算符classc{数据成员没有自增?不能用成员运算符函数和友元运算符函数的比较双目运算符:成员运算符函数带有一个参数,而友元运算符函数带有两个参数。单目运算符:成员运算符函数不带参数,而友元运算符函数带有一个参数成员运算符函数和友元运算符函数的两种调用方式。习惯形式友元运算符函数的调用成员运算符函数的调用a+boperator+(a,b)a.operator+(b)-aoperator-(a)a.operator-()a++operator++(a,0)a.operator++(0)对于双目运算符,将它重载为一个友元运算符函数比重载为成员运算符函数便于使用。若运算符的操作要修改类对象的状态,则选成员运算符函数较好如运算符所需的操作数(尤其是第一个操作数需)希望有隐式类型转换,则必须用友元成员运算符函数和友元运算符函数的比较双目运算符:成员运算符函++和--运算符的重载对前缀方式++ob,可以用运算符函数重载为:ob.operator++();(成员函数)或operator++(X&ob);(友元函数)对后缀方式ob++,可以用运算符函数重载为:ob.operator++(int);(成员函数)或operator++(X&ob,int);(友元函数)调用时参数int一般被传递给值0++和--运算符的重载对前缀方式++ob,可以用运算符函数classover{inti1,i2;public:voidinit(intI1,intI2){i1=I1;i2=I2;}voidprint(){cout<<i1<<i2<<endl;}overoperator++(){++i1;++i2;return*this;}overoperator++(int){overtemp(*this);i2++;i1++;returntemp;}friendoveroperator--(over&op){--op.i1;--op.i2;returnop;}friendoveroperator--(over&op,int){overtemp;temp.i1=op.i1--;temp.i2=op.i2--;returntemp;}};voidmain(){overb1,b2,b3,b4;b1.init(4,2);b2.init(2,5);b3.init(8,3);b4.init(3,6);(++b1).print();(b2++).print();(--b3).print();(b4--).print();(b1.operator++()).print();(b2.operator++(0)).print();(operator--(b3)).print();(operator--(b4,0)).print();}classover{流类库stdio.h中提供的printf和scanf的缺陷非类型安全:编译系统对函数原型进行检查(参数个数、参数类型),可以避免许多错误,但是编译系统对printf()和scanf()函数只检查第一个参数(参数个数和类型信息包含在第一个参数中),所以,其他的错误无法在编译时被发现。不可扩充性:不能对类对象进行输入输出C++流库流:数据从源(数据的生产者)到漏(数据的消费者)的流动。流库:为完成输入输出工作而预定义的类的集合,这些类构成一个层次结构的系统输出:将一个对象的状态换成一个字符序列,输出到某个地方。向“流”中添加数据

输入:从某个地方接收到一个字符序列,将其转换成一个对象的状态所要求的格式。从“流”中获取数据

流类库stdio.h中提供的printf和scanf的缺陷流类库流类库的基类:streambuf和ios类,所有的流类都是从它们直接或间接派生出的streambuf类:负责缓冲区的处理。缓冲区由一个字符序列和两个指针组成,指针分别指向字符将被插入或被取出的位置。streambuffilebufstrstreambufconbuffilebuf:能够处理文件。把filebuf同某个文件的描述字相联系称为打开该文件。strstreambuf:提供了在内存中进行提取和插入操作的缓冲区管理。conbuf:能处理输出,为输出操作提供缓冲区管理。流类库流类库的基类:streambuf和ios类,所有的流类流类库ios类:提供了使用流类的接口,都有一个指向streambuf的指针。ios是一个虚基类,定义了用于格式化输入输出及出错处理的成员函数。iosistreamostreamiostreamios类派生出4个类:输入流(istream)针对系统全部的预定义类型重载了输入运算符“>>”,该类提供了流的大部分输入操作输出流(ostream)针对系统全部的预定义类型重载了输入运算符“<<”,该类提供了流的主要输出操作:文件流(fstreambase):提供了文件流的公共操作串流(strstreambase):专门处理串流流类库ios类:提供了使用流类的接口,都有一个指向strea流类库4种基本流类组合派生出实用流:输入/输出流(iostream):输入/输出文件流(fstream):输入/输出串流(strstream):屏幕输出流(constream):输入文件流(ifstream):输出文件流(ofstream):输入串流(istrstream):输出串流(ostrstream):例:iostream是通过多重继承从输入流类istream和输出流类ostream派生而来的。支持双向操作。classios;classistream:virtualpublicios;classostream:virtualpublicios;classiostream:publicistream,publicostream;流类库4种基本流类组合派生出实用流:在istream、ostream、iostream类的基础上重载“=”,产生istream_withassign、ostream_withassign和 iostream_withassign流类库在istream、ostream、iostream类的基础上流类库执行C++程序时,系统自动打开几个预定义流,用户在程序中直接使用iostream.h:标准I/O流头文件,在该文件中对各个流类定义了各自的全局对象。

cin:是istream_withassign类的对象,称为标准输入流,缺省为键盘cout:是ostream_withassign类的对象,称为标准输出流,缺省为显示器cerr和clog:是ostream_withassign类的对象,称为标准错误输出流,固定关联到显示器。cerr没有被缓冲,因而发送给它的任何内容都立即输出;相反clog被缓冲了,只有当缓冲区满时才输出流类库执行C++程序时,系统自动打开几个预定义流,用户在程序例:要为用户计算平均价格,但用户的输入不恰当(例如输入发除数为零),下面的代码能检测用户所输入的数值并显示出相应的错误信息。cout<<“Howmanyunitsdidyousell?”;cin>>num;if(num==0){cerr<<“Theaveragecannotbecomputer.\n”);}else{…}例:要为用户计算平均价格,但用户的输入不恰当(例如输入发除数预定义类型的输入输出输入运算符>>:双目运算符,有两个操作数,左操作数是istream类的一个对象,右操作数既可以是一个预定义类型的变量,也可以是重载了该运算符的类对象缺省时:>>运算符跳过空白符,然后读入与输入变量类型相对应的值。因此,给一组变量输入值时可用空格或换行把键入的数值间隔开。intn;floatx;cin>>n>>x;当输入字符串时:>>运算符跳过空白符,读入以下的非空白字符,直到遇到另一个空白字符为止,并在串尾放一个字符\0。char*str;cin>>str;输入:objectprogramming!则:str=“object”预定义类型的输入输出输入运算符>>:双目运算符,有两个操作数预定义类型的输入输出不同类型的变量一起输入时,系统除检查是否含有空白符外,还完成输入数据与变量类型的匹配intn;floatx;cin>>n>>x;输入:35.7889.25则:n=35x=.78输入运算符>>采用左结合方式工作,并返回它的左操作数。预定义类型的输入输出不同类型的变量一起输入时,系统除检查是否预定义类型的输入输出输出运算符:双目运算符,有两个操作数,左操作数是ostream类的对象,右操作数既可以是一个预定义类型的变量,也可以是重载了该运算符的类对象<<运算符:采用左结合方式工作,并且返回它的左操作数。使用<<进行输出操作时,编译程序根据出现在运算符右边的变量的类型决定调用重载该运算符的哪个版本重载不能改变运算符的优先级cout<<x&y<<‘\n’;预定义类型的输入输出输出运算符:双目运算符,有两个操作数,左运算符<<和>>的重载<<:重载格式为ostream&operator<<(ostream&stream,CLASSAa){对于类CLASSA的输出操作returnstream;}说明:假设定义为成员函数则左运算数应当是调用运算符函数的类的对象,但重载时左操作数是流第一个参数为ostream类的一个引用第二个参数为自定义的类类型的对象返回第一个参数,使<<能连续使用例:cout<<a<<b;operator<<(cout,a)运算符<<和>>的重载<<:重载格式为为复数类型重载<<#include<iostream.h>classcomplex{private:floatRe,Im;public:complex(floatr=0,floati=0){Re=r;Im=i;}

friendostream&operator<<(ostream&s,complexc){s<<c.Re<<“+”;s<<c.Im<<“i”<<endl;returns;}};voidmain(){complexa(3,4),b(5,6);cout<<a<<b;}

为复数类型重载<<#include<iostream.h>为复数类型重载>>#include<iostream.h>classcomplex{private:floatRe,Im;public:complex(floatr=0,floati=0){Re=r;Im=i;}

friendistream&operator>>(istream&s,complexc){s>>c.Re>>c.Im;returns;}};voidmain(){complexa(3,4),b(5,6);cin>>a>>b;}

输入1234(注意不能输入1,2,3,4逗号不是间隔)a=?为复数类型重载>>#include<iostream.h>运算符<<和>>的重载istream&operator>>(istream&in,user_type&obj){…returnin;}注意:返回类型是类对象的引用,把几个输入运算符放在同一条语句中时,该重载函数仍能正确工作。第二个参数为引用,因为要修改实参假设定义为成员函数则cin>>d;解释为:cin.operator>>(d);相当于为istream类重载输入运算符运算符<<和>>的重载istream&operator>>格式控制格式控制方法:使用ios类中有关格式控制的成员函数使用称为控制符的特殊类型函数用ios类成员函数控制格式在ios类中说明了数据成员longx_flags,存放控制输入输出格式的状态标志,每个状态标志占一位。详见p138设定了某个状态标志,则x_flags中对应位为1,否则为0,可以几个标志并存例:对于12.0,如未置showpoint位,则输出12,若置此位,输出12.000000格式控制格式控制方法:格式控制用成员函数操作状态标志设置状态标志setf原型:longios::setf(longflags);使用:stream_obj.setf(ios::scientific);其中:stream_obj多为cin、cout设置多个标志时,彼此用或运算符|分隔例:cout.setf(ios::dec|ios::scientific);清除状态标志unsetf原型:longios::unsetf(longflags);作用:把指定的状态标志位置0,即清除指定的状态标志取状态标志flags原型:longios::flags();longios::flags(longflags);作用:取状态标志格式控制用成员函数操作状态标志设置状态标志setf原型:lo操作状态标志的成员函数举例#include<iostream.h>voidshowflags(longf){longi;for(i=0x8000;i;i=i>>1)if(i&f)cout<<“1”;elsecout<<“0”;cout<<“\n”;}voidmain(){longf;

f=cout.flags();showflags(f);

cout.setf(ios::showpos|ios::scientific);f=cout.flags();

showflags(f);

cout.unsetf(ios::scientific);f=cout.flags();showflags(f);}操作状态标志的成员函数举例#include<iostrea格式控制设置域宽原型:intios::width();返回当前的域宽值intios::width(intwid);设置域宽,并返回原域宽特点:设置的域宽仅对下一个流输出操作有效,当一次输出操作完成后,域宽恢复为0设置填充字符:当输出值不足以填满域宽时用该字符来填充原型:charios::fill();返回当前的填充字符charios::fill(charc)用参数c重新设置填充字符, 并返回填充前的字符设置显示精度原型:intios::precision();返回当前的显示精度intios::precision(intnum)用参数num重新设置显 示精度,并返回设置前的显示精度格式控制设置域宽原型:intios::width();返回上述成员函数举例#include<iostream.h>voidmain(){cout<<“defaultwidthis”<<cout.width()<<“\n”;cout<<“defaultfillis”<<cout.fill()<<“\n”;cout<<“defaultprecisionis”<<cout.precision()<<“\n”;cout<<666<<““<<123.45678<<“\n”;

cout.precision(3);cout.width(8);cout<<666<<““<<123.45678<<““<<456.78<<“\n”;cout<<“currentwidthis”<<cout.width()<<“\n”;cout<<“currentprecisionis”<<cout.precision()<<“\n”;

cout<<fill(‘*’);cout.width(8);cout<<666<<““<<123.45678<<“\n”;}defaultwidthis0defaultfillisdefaultprecisionis6666123.457666123457currentwidthis0currentprecisionis3*****666123上述成员函数举例#include<iostream.h>格式控制结论:缺省域宽为0;缺省的填充字符为空格;缺省的输出精度为0,即按数据的实际精度输出设置了显示精度后,若数据的实际精度与设置的精度不一致,则输出方法如下:实际精度大于设置精度时,四舍五入后按设置的精度输出;实际精度小于设置的精度时,按实际精度输出设置域宽后,只对其后最接近它的第一个输出有影响,第一个输出完成后系统立即把域宽置0格式控制结论:用控制符控制格式ios类的成员函数控制输入输出格式时,必须由流对象来调用它们,且不能把它们直接嵌入到输入输出语句中。控制符:类似于函数的运算符。用一个流引用作为参数,并返回同一个流的引用标准控制符:dec:设置十进制转换基格式标志hex:设置十六进制转换基格式标志oct:设置八进制转换基格式标志ws:提取空白字符,仅用于输入endl:插入换行符并刷新流,仅用于输出ends:在串后插入终止空字符,仅用于输出flush:刷新输出流,仅用于输出setbase(intn):设置转换基格式位n(取值0,8,16,10),缺省为0用控制符控制格式ios类的成员函数控制输入输出格式时,必须由用控制符控制格式sesetiosflags(longf):清除由参数f指定的格式位,用于输入输出setfill(intc):设置填充字符,对于右对齐输出,填充左面;对于左对齐输出填充右面。一次设置多次有效。用于输入输出setprecision(intn):设置浮点数精度为n,用于输入输出setw(intn):设置域宽为n,只对下一次的输出操作有效。用于输入输出上述控制符在iostream.h中定义,控制符函数在iomanip.h中定义,使用控制符函数时必须包含这两个头文件用控制符控制格式sesetiosflags(longf):控制符和控制符函数举例#include<iostream.h>#include<iomanip.h>voidmain(){cout<<123<<setw(5)<<456<<88<<“\n”;cout<<123<<setw(5)<<setfill(‘*’)<<456<<setw(5)<<88<<“\n”;}12345688123**456***88控制符和控制符函数举例#include<iostream.控制符和控制符函数举例#include<iostream.h>#include<iomanip.h>voidmain(){floatv1=1360.53;floatv2=300.23;floatv3=84430.23;cout<<setiosflags(ios::showpoint|ios::fixed)<<setprecision(2)<<setfill(‘*’)<<setiosflags(ios::right);cout<<“\nCheckValue:$“<<setw(10)<<v1;cout<<“\nCheckValue:$“<<setw(10)<<v2;cout<<“\nCheckValue:$“<<setw(10)<<v3;}CheckValue:$***1360.53CheckValue:$****300.23CheckValue:$**84430.23控制符和控制符函数举例#include<iostream.用户自定义控制符用途:当要对预先未定义的设备进行操作时,定义自己的控制函数能使得对这类设备的操作变得方便当多次重复使用几个相同的控制符时,可以把这些控制符合并在一个控制函数中,以便于用户使用为输出流定义控制函数的格式为:ostream&manip_name(ostream&str){…returnstr;}为输入流定义控制函数的格式为:istream&manip_name(istream&str){…returnstr;}调用时只要直接写出自定义控制符的名字:manip_name用户自定义控制符用途:用户自定义控制符#include<iostream.h>#include<iomanip.h>ostream&setout(ostream&stream){stream.setf(ios::left);stream<<setw(8)<<setfill(‘*’);returnstream;}voidmain(){cout<<“firstline:”<<setout<<25<<“\n”;cout<<“secondline:”<<setout<<148<<“\n”;}firstline:25******secondline:148*****用户自定义控制符#include<iostream.h>f文件操作方式文件:C++把文件当成字符序列。按照数据的组织形式,可把文件分成ASCII文件和二进制文件ASCII文件:每个字节放一个ASCII代码,表示一个字符,使用方便但占用的存储空间较多。缺省时文件以正文方式打开,即在输入时回车/换行序列转换成字符‘\n’,输出时字符‘\n’转换成回车/换行序列二进制文件:把内存中的数据按其在内存中的存储形式原样写到外存储器中。二进制文件可以节省外存空间,但它的一个字节不对应一个字符打开文件:进行文件的输入输出,首先建立一个文件流,把该流和实际的文件相关联关闭文件:取消文件和流的关联文件流:输入文件流、输出文件流、输入/输出文件流文件操作方式文件:C++把文件当成字符序列。按照数据的组织形面向文件的流类fstream.h:“文件流”头文件,在该文件中对各个文件流类进行了定义,但是没有预定义各自的全局对象。因为,在C++中文件类不是标准设备,不能预先定义。在头文件fstream.h中给出了fstreambase、ifstream、ofstream、fstream类的定义。fstreambase是ifstream和ofstream的公共基类,fstream是ifstream和ofstream的派生类,都是公有继承关系执行文件输入输出前的三件事:在程序中包含头文件fstream.h建立文件流,即说明面向文件流类的对象打开文件,即是使某个文件和某以文件流相关联。(文件名和文件的打开方式是传递给构造函数的实参)

面向文件的流类fstream.h:“文件流”头文件,在该文件创建文件流时,需要使用面向文件的流类的构造函数。每个面向文件的流类都有四个重载的构造函数?fstream():创建一个未打开的文件流?fstream(constchar*,intmode,intprot=filebuf::openprot):创建一个打开的文件流第一个参数指定与此文件流相关联的文件的名字第二个参数mode决定文件的打开方式app:追加数据 ate:文件指针移到文件尾in:以输入方式打开文件 out:以输出方式打开文件binary:二进制方式打开文件trunc:文件存在清除原有内容nocreate:文件不存在失败 noreplace:文件存在失败第三个参数决定文件的保护方式:0普通文件;1只读文件;2隐含文件;4系统文件;8备份文件面向文件的流类创建文件流时,需要使用面向文件的流类的构造函数。每个面向文件面向文件的流类创建ifstream类对象时,缺省的mode值为ios::in;创建ofstream类对象时,缺省的mode值为ios::out;未显式指明以二进制方式打开文件,则缺省的方式为文本方式;?fstream(intfd):创建一个打开的文件流,并把它链接到文件柄为fd的文件?fstream(intfd,char*buf,intlen):创建一个打开的文件流,并把它链接到文件柄为fd的文件close函数:关闭与该流对象相链接的文件,并清除流的错误状态open(constchar*name,intmode,intprot=filebuf::openprot)函数:打开名为name的文件例:建立一个输入输出文件流both,把它链接到文件data.dat上,并清除原有的文件内容fstreamboth;both.open(“data.dat”,ios::in|ios::out|ios::trunc);fstreamboth(“data.dat”,”ios::in|ios::out|ios::trunc);面向文件的流类创建ifstream类对象时,缺省的mode值文件的读写文本文件文本文件的读写:使用输入运算符和输出运算符例:把一个整数、浮点数、字符串写到文件data中#include<iostream.h>#include<fstream.h>main(){ofstreamout(“data”);if(!out){cout<<“cannotopenfiledata.”;return0;}out<<256<<““<<198.69<<““<<“C++Language\n”;out.close();return1;}文件的读写文本文件文本文件的读写:使用输入运算符和输出运算符文件的读写二进制二进制文件的读写:使用istream类的公有成员函数get(char&)和ostream类的公有成员函数put(char)例:在屏幕上显示任何文件的内容#include<iostream.h>#include<fstream.h>main(intargc,char*argv[]){charch;ifstreamin(argv[1]);if(!in){cout<<“Cannotopenfile”;return1;}while(!in.eof()){in.get(ch);cout<<ch;}return0;}文件的读写二进制二进制文件的读写:使用istream类的公有流的错误处理流的错误处理第七章运算符重载及流类库运算符重载类运算符和友元运算符++和--运算符的重载流类库运算符“<<”和“>>”的重载格式控制文件操作方式流的错误处理第七章运算符重载及流类库运算符重载运算符重载对基本数据类型,“+”、“–”等,C++用一种简洁的方式工作。例:intx,y,z;z=x+y;若有复数类complex:classcomplex{public:doublereal,imag;complex(doubler=0,doublei=0){real=r;imag=i;}};complexc1(1.1,2.3),c2(2.2,1.3),total;total=c1+c2;运算符重载对基本数据类型,“+”、“–”等,C++用一种运算符重载运算符重载通过创建operator()和一个运算符连用构成运算符函数实现格式:Typeoperator@(参数表){…//(函数定义)}例:intoperator+(x,y){…}返回值type不能是void@表示要重载的运算符,编译时首先检查传递给函数的参数类型,如果看到是自定义的类型,则执行用户自己的函数运算符重载运算符重载通过创建operator()和一个运算符运算符重载complexoperator+(complexom1,complexom2){complextemp;temp.real=om1.real+om2.real;temp.imag=om1.imag+om2.imag;returntemp;}total=c1+c2;(total=operator+(c1,c2);)运算符重载complexoperator+(comple运算符重载说明:只能重载C++语言中原先已有定义的运算符不能重载:..*::?:#不能改变运算符的操作数个数不能改变原有的优先级x=y-a*b;不能改变原有的结合性x=a/b*c;不能改变运算符对预定义类型数据的操作方式+:为加法运算,无法重载而改变它对预定义类型数据的操作方式

重载运算符时至少有一个自定义类型的数据作为操作数运算符重载说明:类运算符成员运算符函数定义的语法形式:classX{…typeoperator@(参数表);…};说明:重载单目运算符,则参数表为空;若运算符为双目运算符,则参数表中有一个操作数。双目运算符重载:classX{…intoperator+(Xa);…};说明:参数作为运算符的右操作数。当前对象作为运算符的左操作数,通过this指针隐含地传递给函数类运算符成员运算符函数定义的语法形式:classcomplex{public:doublereal,imag;complex(doubler=0,doublei=0){real=r;imag=i;}};complexoperator+(complexc){complextemp;temp.real=c.real+real;temp.imag=c.imag+imag;returntemp;}};voidmain(){complexA1(2.3,4.6),A2(3.6,2.8),A3;A3=A1+A2;(解释为:A3=A1.operator+(A2);)}采用成员函数重载双目运算符后,使用的方法:aa@bb;aa.operator@(bb);类运算符双目运算符classcomplex{采用成员函数重载双目运算符后,使类运算符单目运算符单目运算符重载:参数通过this指针隐含地传递给函数classc{intx,y;public:c(inti=0,intj=0){x=i;y=j;}coperator++(){++x;++y;return*this;}};voidmain(){cob(10,20);++ob;ob.operator++();};采用成员函数重载单目运算符后,使用的方法:@aa;aa.operator@();类运算符单目运算符单目运算符重载:classc{采用成员函双目运算符可以被重载为成员函数,但有一种情况:例:成员运算符函数重载了+运算符ob=ob+100解释为ob.operator+(100)但:ob=100+ob;解释为100.operator+(ob)错误类运算符双目运算符可以被重载为成员函数,但有一种情况:类运算符友元运算符友元运算符函数定义的语法形式:friendtypeoperator@(参数表);说明:友元函数没有this指针,若重载的是双目运算符,则参数表中有两个操作数;若重载的是单目运算符,则参数表中有一个操作数友元运算符友元运算符函数定义的语法形式:友元运算符双目运算符classcomplex{public:doublereal,imag;complex(doubler=0,doublei=0){real=r;imag=i;}friendcomplexoperator+(complexa,complexb){complextemp;temp.real=a.real+b.real;temp.imag=a.imag+b.imag;returntemp;}};voidmain(){complexA1(2.3,4.6),A2(3.6,2.8),A3;A3=A1+A2;}采用友元函数重载双目运算符后,使用的方法:aa@bb;operator@(aa,bb);友元运算符双目运算符classcomplex{采用友元函数友元运算符单目运算符classc{intx,y;public:c(inti=0,intj=0){x=i;y=j;}voidshow(){cout<<x<<y;}

//operatorint(){returnx;}friendcoperator++(cop){++op.x;++op.y;

returnop;}};voidmain(){cob(10,20);ob.show();++ob;//cout<<operator++(ob);ob.show();数据成员没有自增?采用友元函数重载单目运算符后,使用的方法:采用引用参数传递操作数,以改变操作数的值operator++(c&op)@aa;operator@(aa);不能用友元函数重载:=()[]->不要改变操作数时,可采用传值的方法。友元运算符单目运算符classc{数据成员没有自增?不能用成员运算符函数和友元运算符函数的比较双目运算符:成员运算符函数带有一个参数,而友元运算符函数带有两个参数。单目运算符:成员运算符函数不带参数,而友元运算符函数带有一个参数成员运算符函数和友元运算符函数的两种调用方式。习惯形式友元运算符函数的调用成员运算符函数的调用a+boperator+(a,b)a.operator+(b)-aoperator-(a)a.operator-()a++operator++(a,0)a.operator++(0)对于双目运算符,将它重载为一个友元运算符函数比重载为成员运算符函数便于使用。若运算符的操作要修改类对象的状态,则选成员运算符函数较好如运算符所需的操作数(尤其是第一个操作数需)希望有隐式类型转换,则必须用友元成员运算符函数和友元运算符函数的比较双目运算符:成员运算符函++和--运算符的重载对前缀方式++ob,可以用运算符函数重载为:ob.operator++();(成员函数)或operator++(X&ob);(友元函数)对后缀方式ob++,可以用运算符函数重载为:ob.operator++(int);(成员函数)或operator++(X&ob,int);(友元函数)调用时参数int一般被传递给值0++和--运算符的重载对前缀方式++ob,可以用运算符函数classover{inti1,i2;public:voidinit(intI1,intI2){i1=I1;i2=I2;}voidprint(){cout<<i1<<i2<<endl;}overoperator++(){++i1;++i2;return*this;}overoperator++(int){overtemp(*this);i2++;i1++;returntemp;}friendoveroperator--(over&op){--op.i1;--op.i2;returnop;}friendoveroperator--(over&op,int){overtemp;temp.i1=op.i1--;temp.i2=op.i2--;returntemp;}};voidmain(){overb1,b2,b3,b4;b1.init(4,2);b2.init(2,5);b3.init(8,3);b4.init(3,6);(++b1).print();(b2++).print();(--b3).print();(b4--).print();(b1.operator++()).print();(b2.operator++(0)).print();(operator--(b3)).print();(operator--(b4,0)).print();}classover{流类库stdio.h中提供的printf和scanf的缺陷非类型安全:编译系统对函数原型进行检查(参数个数、参数类型),可以避免许多错误,但是编译系统对printf()和scanf()函数只检查第一个参数(参数个数和类型信息包含在第一个参数中),所以,其他的错误无法在编译时被发现。不可扩充性:不能对类对象进行输入输出C++流库流:数据从源(数据的生产者)到漏(数据的消费者)的流动。流库:为完成输入输出工作而预定义的类的集合,这些类构成一个层次结构的系统输出:将一个对象的状态换成一个字符序列,输出到某个地方。向“流”中添加数据

输入:从某个地方接收到一个字符序列,将其转换成一个对象的状态所要求的格式。从“流”中获取数据

流类库stdio.h中提供的printf和scanf的缺陷流类库流类库的基类:streambuf和ios类,所有的流类都是从它们直接或间接派生出的streambuf类:负责缓冲区的处理。缓冲区由一个字符序列和两个指针组成,指针分别指向字符将被插入或被取出的位置。streambuffilebufstrstreambufconbuffilebuf:能够处理文件。把filebuf同某个文件的描述字相联系称为打开该文件。strstreambuf:提供了在内存中进行提取和插入操作的缓冲区管理。conbuf:能处理输出,为输出操作提供缓冲区管理。流类库流类库的基类:streambuf和ios类,所有的流类流类库ios类:提供了使用流类的接口,都有一个指向streambuf的指针。ios是一个虚基类,定义了用于格式化输入输出及出错处理的成员函数。iosistreamostreamiostreamios类派生出4个类:输入流(istream)针对系统全部的预定义类型重载了输入运算符“>>”,该类提供了流的大部分输入操作输出流(ostream)针对系统全部的预定义类型重载了输入运算符“<<”,该类提供了流的主要输出操作:文件流(fstreambase):提供了文件流的公共操作串流(strstreambase):专门处理串流流类库ios类:提供了使用流类的接口,都有一个指向strea流类库4种基本流类组合派生出实用流:输入/输出流(iostream):输入/输出文件流(fstream):输入/输出串流(strstream):屏幕输出流(constream):输入文件流(ifstream):输出文件流(ofstream):输入串流(istrstream):输出串流(ostrstream):例:iostream是通过多重继承从输入流类istream和输出流类ostream派生而来的。支持双向操作。classios;classistream:virtualpublicios;classostream:virtualpublicios;classiostream:publicistream,publicostream;流类库4种基本流类组合派生出实用流:在istream、ostream、iostream类的基础上重载“=”,产生istream_withassign、ostream_withassign和 iostream_withassign流类库在istream、ostream、iostream类的基础上流类库执行C++程序时,系统自动打开几个预定义流,用户在程序中直接使用iostream.h:标准I/O流头文件,在该文件中对各个流类定义了各自的全局对象。

cin:是istream_withassign类的对象,称为标准输入流,缺省为键盘cout:是ostream_withassign类的对象,称为标准输出流,缺省为显示器cerr和clog:是ostream_withassign类的对象,称为标准错误输出流,固定关联到显示器。cerr没有被缓冲,因而发送给它的任何内容都立即输出;相反clog被缓冲了,只有当缓冲区满时才输出流类库执行C++程序时,系统自动打开几个预定义流,用户在程序例:要为用户计算平均价格,但用户的输入不恰当(例如输入发除数为零),下面的代码能检测用户所输入的数值并显示出相应的错误信息。cout<<“Howmanyunitsdidyousell?”;cin>>num;if(num==0){cerr<<“Theaveragecannotbecomputer.\n”);}else{…}例:要为用户计算平均价格,但用户的输入不恰当(例如输入发除数预定义类型的输入输出输入运算符>>:双目运算符,有两个操作数,左操作数是istream类的一个对象,右操作数既可以是一个预定义类型的变量,也可以是重载了该运算符的类对象缺省时:>>运算符跳过空白符,然后读入与输入变量类型相对应的值。因此,给一组变量输入值时可用空格或换行把键入的数值间隔开。intn;floatx;cin>>n>>x;当输入字符串时:>>运算符跳过空白符,读入以下的非空白字符,直到遇到另一个空白字符为止,并在串尾放一个字符\0。char*str;cin>>str;输入:objectprogramming!则:str=“object”预定义类型的输入输出输入运算符>>:双目运算符,有两个操作数预定义类型的输入输出不同类型的变量一起输入时,系统除检查是否含有空白符外,还完成输入数据与变量类型的匹配intn;floatx;cin>>n>>x;输入:35.7889.25则:n=35x=.78输入运算符>>采用左结合方式工作,并返回它的左操作数。预定义类型的输入输出不同类型的变量一起输入时,系统除检查是否预定义类型的输入输出输出运算符:双目运算符,有两个操作数,左操作数是ostream类的对象,右操作数既可以是一个预定义类型的变量,也可以是重载了该运算符的类对象<<运算符:采用左结合方式工作,并且返回它的左操作数。使用<<进行输出操作时,编译程序根据出现在运算符右边的变量的类型决定调用重载该运算符的哪个版本重载不能改变运算符的优先级cout<<x&y<<‘\n’;预定义类型的输入输出输出运算符:双目运算符,有两个操作数,左运算符<<和>>的重载<<:重载格式为ostream&operator<<(ostream&stream,CLASSAa){对于类CLASSA的输出操作returnstream;}说明:假设定义为成员函数则左运算数应当是调用运算符函数的类的对象,但重载时左操作数是流第一个参数为ostream类的一个引用第二个参数为自定义的类类型的对象返回第一个参数,使<<能连续使用例:cout<<a<<b;operator<<(cout,a)运算符<<和>>的重载<<:重载格式为为复数类型重载<<#include<iostream.h>classcomplex{private:floatRe,Im;public:complex(floatr=0,floati=0){Re=r;Im=i;}

friendostream&operator<<(ostream&s,complexc){s<<c.Re<<“+”;s<<c.Im<<“i”<<endl;returns;}};voidmain(){complexa(3,4),b(5,6);cout<<a<<b;}

为复数类型重载<<#include<iostream.h>为复数类型重载>>#include<iostream.h>classcomplex{private:floatRe,Im;public:complex(floatr=0,floati=0){Re=r;Im=i;}

friendistream&operator>>(istream&s,complexc){s>>c.Re>>c.Im;returns;}};voidmain(){complexa(3,4),b(5,6);cin>>a>>b;}

输入1234(注意不能输入1,2,3,4逗号不是间隔)a=?为复数类型重载>>#include<iostream.h>运算符<<和>>的重载istream&operator>>(istream&in,user_type&obj){…returnin;}注意:返回类型是类对象的引用,把几个输入运算符放在同一条语句中时,该重载函数仍能正确工作。第二个参数为引用,因为要修改实参假设定义为成员函数则cin>>d;解释为:cin.operator>>(d);相当于为istream类重载输入运算符运算符<<和>>的重载istream&operator>>格式控制格式控制方法:使用ios类中有关格式控制的成员函数使用称为控制符的特殊类型函数用ios类成员函数控制格式在ios类中说明了数据成员longx_flags,存放控制输入输出格式的状态标志,每个状态标志占一位。详见p138设定了某个状态标志,则x_flags中对应位为1,否则为0,可以几个标志并存例:对于12.0,如未置showpoint位,则输出12,若置此位,输出12.000000格式控制格式控制方法:格式控制用成员函数操作状态标志设置状态标志setf原型:longios::setf(longflags);使用:stream_obj.setf(ios::scientific);其中:stream_obj多为cin、cout设置多个标志时,彼此用或运算符|分隔例:cout.setf(ios::dec|ios::scientific);清除状态标志unsetf原型:longios::unsetf(longflags);作用:把指定的状态标志位置0,即清除指定的状态标志取状态标志flags原型:longios::flags();longios::flags(longflags);作用:取状态标志格式控制用成员函数操作状态标志设置状态标志setf原型:lo操作状态标志的成员函数举例#include<iostream.h>voidshowflags(longf){longi;for(i=0x8000;i;i=i>>1)if(i&f)cout<<“1”;elsecout<<“0”;cout<<“\n”;}voidmain(){longf;

f=cout.flags();showflags(f);

cout.setf(ios::showpos|ios::scientific);f=cout.flags();

showflags(f);

cout.unsetf(ios::scientific);f=cout.flags();showflags(f);}操作状态标志的成员函数举例#include<iostrea格式控制设置域宽原型:intios::width();返回当前的域宽值intios::width(intwid);设置域宽,并返回原域宽特点:设置的域宽仅对下一个流输出操作有效,当一次输出操作完成后,域宽恢复为0设置填充字符:当输出值不足以填满域宽时用该字符来填充原型:charios::fill();返回当前的填充字符charios::fill(charc)用参数c重新设置填充字符, 并返回填充前的字符设置显示精度原型:intios::precision();返回当前的显示精度intios::precision(intnum)用参数num重新设置显 示精度,并返回设置前的显示精度格式控制设置域宽原型:intios::width();返回上述成员函数举例#include<iostream.h>voidmain(){cout<<“defaultwidthis”<<cout.width()<<“\n”;cout<<“defaultfillis”<<cout.fill()<<“\n”;cout<<“defaultprecisionis”<<cout.precision()<<“\n”;cout<<666<<““<<123.45678<<“\n”;

cout.precision(3);cout.width(8);cout<<666<<““<<123.45678<<““<<456.78<<“\n”;cout<<“currentwidthis”<<cout.width()<<“\n”;cout<<“currentprecisionis”<<cout.precision()<<“\n”;

cout<<fill(‘*’);cout.width(8);cout<<666<<““<<123.45678<<“\n”;}defaultwidthis0defaultfillisdefaultprecisionis6666123.457666123457currentwidthis0currentprecisionis3*****666123上述成员函数举例#include<iostream.h>格式控制结论:缺省域宽为0;缺省的填充字符为空格;缺省的输出精度为0,即按数据的实际精度输出设置了显示精度后,若数据的实际精度与设置的精度不一致,则输出方法如下:实际精度大于设置精度时,四舍五入后按设置的精度输出;实际精度小于设置的精度时,按实际精度输出设置域宽后,只对其后最接近它的第一个输出有影响,第一个输出完成后系统立即把域宽置0格式控制结论:用控制符控制格式ios类的成员函数控制输入输出格式时,必须由流对象来调用它们,且不能把它们直接嵌入到输入输出语句中。控制符:类似于函数的运算符。用一个流引用作为参数,并返回同一个流的引用标准控制符:dec:设置十进制转换基格式标志hex:设置十六进制转换基格式标志oct:设置八进制转换基格式标志ws:提取空白字符,仅用于输入endl:插入换行符并刷新流,仅用于输出ends:在串后插入终止空字符,仅用于输出flush:刷新输出流,仅用于输出setbase(intn):设置转换基格式位n(取值0,8,16,10),缺省为0用控制符控制格式ios类的成员函数控制输入输出格式时,必须由用控制符控制格式sesetiosflags(longf):清除由参数f指定的格式位,用于输入输出setfill(intc):设置填充字符,对于右对齐输出,填充左面;对于左对齐输出填充右面。一次设置多次有效。用于输入输出setprecision(intn):设置浮点数精度为n,用于输入输出setw(intn):设置域宽为n,只对下一次的输出操作有效。用于输入输出上述控制符在iostream.h中定义,控制符函数在iomanip.h中定义,使用控制符函数时必须包含这两个头文件用控制符控制格式sesetiosflags(longf):控制符和控制符函数举例#include<iostream.h>#include<iomanip.h>voidmain(){cout<<123<<setw(5)<<456<<88<<“\n”;cout<<123<<setw(5)<<setfill(‘*’)<<456<<setw(5)<<88<<“\n”;}12345688123**456***88控制符和控制符函数举例#include<iostream.控制符和控制符函数举例#include<iostream.h>#include<iomanip.h>voidmain(){floatv1=1360.53;floatv2=300.23;floatv3=84430.23;cout<<setiosflags(ios::showpoint|ios::fixed)<<setprecision(2)<<setfill(‘*’)<<setiosflags(ios::right);cout<<“\nCheckValue:$“<<setw(10)<<v1;cout<<“\nCheckValue:$“<<setw(10)<<v2;cout<<“\nCheckValue:$“<<setw(10)<<v3;}CheckValue:$***1360.53CheckValue:$****300.23CheckV

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论