1、83第五章 算符重载与入出流操作http:/ 27 中,当实现复型数 c=a+b 的运算时是利用类的成员函数进行的。在实用中所期望的是直接利用上式的运算表达式而求解。本章将讨论的算符重载便是解决此类需求的一种技术手段。另一方面本章还将讲述在 C+语言中如何使用标准流入出(cin 和 coutclass Timeint sec,min,hour;friend void operator!(Timepublic:Time (long);Time (int,int);Time (int,float);Time:Time(long s)hour=s/3600;min=s%3600/60;sec=s%3
2、600%60;Time:Time(int m,int s)hour=m/60;min=m%60;sec=s;Time:Time(int h,float ms)hour=h;min=(int)ms;sec=(int)(ms-min)*60);void operator!(Time public:Time(int h,int m,int s):hour(h),min(m),sec(s)operator unsigned long()return(unsigned long)hour*3600+(unsigned long)min*60+(unsigned long)sec;operator dou
3、ble()return(double)hour*60.+(double)min+(double)sec/60.;operator float()return(float)hour+(float)min/60.+(float)sec/3600.;void main()Time ts(12,48,53);unsigned long t1_s=ts;double t2_s=ts; /等效于 double t2_s; t2_s=(double)ts;float t3_s=ts;cout 或 cout”则是在类( 派生类)中定义的重载算符函数。之所以要简要讲述这些原理是因为马上讨论的一系列输入输出保留名
4、并不是 C+语言本身定义的,而是在另一套专门的 “系统类 ”MFC(Microsoft Foundation Class)中定义的。这一点在学习时要基本明确才能较好地灵活运用。3.2 流操作符流操作符是一类全局函数,并是 ostream 和 istream 类的友元,分别在 iostream.h 和 iomanip.h 头文件中被声明。此类函数也用在“”或“ihexlcjs;输入顺序必须键入:十进制的 i 值、十六进制的 l 值,紧跟一个字符 (对应 c)、十六进制的 j 值,紧跟一个字串后回车。其中数字或字串必须后跟空白符(空格或 Tab)代表前一顶结束。但若数字后的字串首字符是非数字,则用
5、于分隔的空白符可省略(对十六进制而言,AF 也是数字) 。也就是非数字的首字符兼起前一数字项结束的作用。二回车换行函数 endl此函数用于产生一个n码,即在输出流中插入 0x0d0a 内码。所以 coutcd;此时的输入:x y与 xy等效。使用 ws 函数后,这个效果始终存在,但对数值变量无效。3.3 带参数的流操作符以下的函数以函数参数的形式来定义所需要的具体格式。使用这些函数时头文件 iostream.h 和iomanip.h 的声明是不能缺少的。一入出域宽度设置函数 setw(int)此函数用整数参数来指定入出域的宽度。相当于 C 语言库函数 scanf、printf 中和格式符图 5
6、-1 C+语言流入 /出类的派生89的作用。该函数的设置效果仅对其后的一个数据项有效。当用于输出时,若所输出的实际宽度小于设定的数据域宽度,则数据缺省一律向右对齐,反之则按数据的实际宽度输出。当用于输入时,若输入数据的实际宽度超过设定的数据域宽时,超出的数据部分被截断且被作为下一项输入数据内容。利用此特性可以防止在变量输入时出现的越界情况,但用不好也易出错。例 9:char *f =”12345”,*g =”678”;coutsetw(4)fg;coutvoid main()cout.setf(ios:hex,ios:basefield);cout#includeint i=63;float
7、pai=3.14;cout.setf(ios:hex,ios:basefield);cout.setf(ios:showbase);coutostream i、coutvoid main()char true=Y,*s1=”Menu mode select:”, *s2=”The students name is”;coutab;时,若只输入了 a,而末输入 b,则 a 单元中并未收到实际输入的值,命令的执行也并未结束而必须待输入了全部数据并打入回车键,系统才将存于缓冲区中的信息转储到相应的变量中去。4 标准流式入出的操作符的重载标准流式入出操作符“”与第一节中讨论的算符并无区别。由于这两个符
8、号是全局使用的,重载当属类外算符重载这一类。同上节讨论 put,write 函数性质一样,为实现入出的流方式,用类声明时都应使用引用类型而带回本对象首地址。为减少大量参数的复制,也提倡使用引用类型。例 23:#include#includeclass Studentfriend ostreamofstream式中的“打开方式常量”就是 C 文件中定义式中的文件类型符的另一种形式。这个常量是在流文件类的基类 ios 中以枚举型常数形式定义的。其定义如下:enum open_modein = 0x1, /进行读操作。out=0x2, /进行写操作。ate=0x4, /初打开文件时,文件指针一定定位
9、到文件末尾备写。app=0x8, /每次写文件时,文件指针都自动定义到文件末尾作为 append。trunc=0x10; /当写文件时,将文件当前指针以后的原有内容全部删除。nocreate=0x20, /若文件已存在,则不新建文件,否则打开失败。noreplace=0x40, /若文件已存在,则不取代同名文件,并使打开失败。binary=0x80, /打开以二进制方式读写,以上三种则为 text 方式。;这些常量可以组合使用,由于每种方式是一个二进制位,所以组合时应以或操作做连接算符。如输出时将文件指针处以后的原内容全部删除,就可写成:“ios:out|ios:turnc;”的格式(即 0x
10、12) 。而在 C 语言的文件类型符中对应这个方式的格式符是“wt” 。又如以二进制方式写就应写成:“ios:out|ios:binary”(即 0x82) 。不过在选用方式常量组合时必须注意所用的类,使其不要发生矛盾。如在 ifstream 类对象文件中用 ios:out 方式常量以后,也是不可能实现对文件的写操作的。因为 ifstream 类中没有定义用作输出的算符和函数。二打开流文件的函数当文件在执行过程中要重复打开或要改变打开方式时,就要靠函数 open()来实现文件的打开了。其格式是:文件对象名.open(char *filename,打开方式常量表);例 24:96#include
11、 void main()fstream fl;fl.open(“test.dat”,ios:out|ios:binary);本例以二进制方式向磁盘写 test.dat 文件的内容,即使遇到 0x0d 也按其二进格式照写入盘,而不按“回车换行”处理(0x0d0a)。三流文件关闭函数对应文件关闭的函数是 close()使用格式非常简单:文件对象名.close();同样,在程序正常结束后,会自动关闭文件,从而可以省略放置于程序尾部的关闭函数。5.3 C+语言流文件读写函数和算符的应用同 C 语言的流文件操作一样,在 C+语言的三个文件类中分别定义了多种专用于文件读写的成员函数。当然在 ifstrea
12、m 和 ofstream 类中只分别定义了用于输入和输出的函数。而在 fstream 类中则包含了所有的函数及算符函数。由于入出函数很多,本书只讨论其中较为常用的部分。一读单个字符的函数 get()get()函数是一个具有许多重载函数的大家族。这里只讲解两个使用类型。读取一个字符在类中的声明是:istream 所以在使用时可以直接给定一个字符型变量。例 25:char ch;fstream f(“test.txt”, ios:in);f.get(ch);执行本例后,文件当前指针处的一个字节被放入变量 ch 中且指针值自动加一。读取一串字符在类中的声明是:istream 对声明中的参数说朋如下:
13、char 表示的是用来存放字串的指针。第二个 int 型参数是要读入的字串长度值。最后一个参数是代表读入结束的字符,缺省则为回车换行。例 26:char p1025;fstream f(“test.txt”,ios:in);f.get(p,1024, 0);本例指定 0x00 为输入结束符。由于 get 只用于输入,所以可以推论,在类 ofstream 中是不可能支持这个函数的。三读取一行字符在类中的声明是:istream 参数说明与上一个函数完全一样,不再重复。实际上,本函数除了名字不同外,与前一函数无本质区别。四用流输入输出算符实现磁盘文件的输入输出操作C+语言的标准输入流算符和#include#includevoid main()int i=30;float f=12.34;char c;fstream fl(“sf”,ios:out|ios:in);97if(!fl) cerrcc; /字符串“I=”读出后不使用fl+i; /i 加 1 后从盘上读出 i 仍为 30coutclass Aint i;A *p;public:A()p=NULL;A(int x):i(x)p=new Ax;void main()A a(5);a0=0;!a0; /最后的显示结果为:I=0结合例 23 请思考下面两个问题:例中的“cout”算符重载来代替 main()中的类对象初始化。