1、程序设计实习课程 (C+Programming Practice)程序设计实习第十八讲 输入输出流和文件操作主讲教师:田永鸿http:/ base string name()return basename;virtual void print(ostream&os)osbasename;private:basename;class derived void print()print(ostream&os);os“”mem;private:int meme;class derived:public base void print()base:print(os);os“”mem;private:i
2、nt meme;同时,基类及派生类也应该定义构造函数和析构函数。base:base(string name):basename(name);base:base();derived:derived(string name,int val):base(name),mem(val);derived:derived();3北京大学程序设计实习课程课堂问题(2)3.下列关于重载函数和虚函数的辨析描述中,理解不正确的是:a)重载函数处理的是同一类层次上的同名函数问题,而虚函数处理的是不同派生层次上的同名函数问题。b)重载函数要求函数有相同的函数名称,不管返回值类型是否相同,但参数序列必须不同,而虚函数则要
3、求函数名、参数序列和返回值类型完全相同。c)重载函数和虚函数都必须是类成员函数,但重载函数一般功能类似,而虚函数一般功能有所不同,甚至基类虚函数的函数体可以为空,具体功能在派生类中添加。d)重载函数在编译时,根据传递参数序列的不同,确定具体调用表现多态性,而虚函数在运行时,根据基类指针或引用所指向对象的不同,确定具体调用表现出多态性。4北京大学程序设计实习课程课堂问题(3)4.请写出运行时输出的结果 class A public:A()virtual void func()cout A:func endl;A()virtual void fund()cout A:fund endl;class
4、 B:public A public:B()func();void fun()func();B()fund();class C:public B public:C()void func()cout C:func endl;C()fund();void fund()cout C:fund endl;main()C c;A:funcC:fundA:fund5北京大学程序设计实习课程内容提要o输入输出流o文件操作o作业6北京大学程序设计实习课程输入输出流o流的概念模型oC+中与流操作相关的类及其继承关系o输入输出流对象:cin,cout,cerr,clogo输出流o输入流o无格式输入输出o流操纵算子
5、o流格式状态7北京大学程序设计实习课程流的概念模型o流-可以看作一个无限长的二进制数字序列o通过读写指针进行流的读和写(以字节为单位)1010111010101110将流上的数据读进变量x1 0 1 0 1 1 1 011100010将y的值写入流yx8北京大学程序设计实习课程流的概念模型o输出流 n可以看作一端无限,另一端通过写指针不停地向后写入新内容的单向流,11 00011010写指针9北京大学程序设计实习课程流的概念模型o输入流 n可以看作一端无限,另一端通过读指针不停地从流中读取新内容的单向流,读出的内容从流中删去。11 00011010读指针10北京大学程序设计实习课程有格式读写和
6、无格式读写o有格式读写,以某种数据类型为单位读写n例如:读一个整数,写一个浮点数等;o无格式读写,以字节为单位读写,不区分其中的内容n例如:读20个字节,写50个字节等;11北京大学程序设计实习课程缓冲区刷新o向输出流中写数据时,通常是先向缓冲区中写,当缓冲区写满时,才真正向输出流写o也可以通过函数在程序中主动将缓冲区内容写入输出流。12北京大学程序设计实习课程C+中与流操作相关的类及其继承关系iosistreamostreamifstreamiostreamofstreamfstream13北京大学程序设计实习课程标准流对象o输入流对象ncin 与标准输入设备相连o输出流对象:ncout 与
7、标准输出设备相连 ncerr 与标准错误输出设备相连,非缓冲输出 nclog 与标准错误输出设备相连,缓冲输出 14北京大学程序设计实习课程输出流o流插入运算符 cout “Good morning!n”;不刷新缓冲区 cout “Good”;不刷新缓冲区 cout “morning!”;不刷新缓冲区 cout endl;刷新缓冲区 cout flush;刷新缓冲区ncout显示内容的时候会先将欲显示内容存放在缓存区,待刷新的时候才将内容付显,而具有刷新功能的语句为endl或者flush。15北京大学程序设计实习课程输出流o输出表达式 cout (47+53);/将表达式括起来,/避免优先级冲
8、突。o连续使用流插入运算符 cout “ha ha”(100+100)endl;相当于 (cout “ha ha”)(100+100)endl;16北京大学程序设计实习课程输出流o输出 char*类型的变量 char*string=“test”;cout string;/以strlen()给出的长度计 /输出字符串内容 /test cout static_cast(string);/输出 string的地址 /0 x0042501c -会变的!用法:static_cast (a)将地址a转换成类型T,T和a必须是指针、引用、算术类型或枚举类型。表达式static_cast(a),a的值转换为模
9、板中指定的类型T。在运行时转换过程中,不进行类型检查来确保转换的安全性。17北京大学程序设计实习课程输出流o用成员函数put输出字符 cout.put(A);oput的连续使用 cout.put(A).put(a);18北京大学程序设计实习课程输入流o读取运算符 int x,y;cin x;cin y;或者 cin x y;19北京大学程序设计实习课程输入流o读取运算的返回值o重载运算符的定义:istream&operator(istream&input,A&a).return input;o返回的是输入流的引用(引用本身是地址),在读取不成功时,该地址被置成 0.所以可以用如下方法判输入结束
10、:int x;while(cinx)20北京大学程序设计实习课程输入流o成员函数 ocin.get()读入一个字符(包括空白字符),返回该字符;char*cin.get(char*buffer,int size,char delim=n)或者读size 1 个字符入buffer,或者遇到n;在buffer最后加0,分隔符留在输入流.ochar*cin.getline(char*buffer,int size,char delim=n)或者读size 1 个字符入buffer,或者遇到n;在buffer最后加0,分隔符从流去掉.obool cin.eof()返回输入是否结束标志.21北京大学程序
11、设计实习课程输入流ocin.peek():返回下一个字符,但不从流中去掉.ocin.putback(char ch):将字符ch放回输入流ocin.gcount():返回上次读入的字节数ocin.ignore(int nCount=1,int delim=EOF):从流中删掉最多nCount个字符,遇到EOF时结束。22北京大学程序设计实习课程无格式输入输出o用read,write 进行指定字节数的输入输出const int SIZE=80;char bufferSIZE;cin.read(buffer,20);/cin.get(buffer,20);cout.write(buffer,cin
12、.gcount();/gcount返回上次读入的字节数cout endl;输入:Using the read,write and gcount member functions 输出:Using the read,write23北京大学程序设计实习课程流操纵算子o整数流的基数:流操纵算子dec,oct,hex,setbaseo浮点数的精度(precision,setprecision)o设置域宽(setw,width)o用户自定义的流操纵算子24北京大学程序设计实习课程流操纵算子o整数流的基数:流操纵算子dec,oct,hex int n=10;cout n endl;cout hex n “
13、n”dec n “n”oct n setprecision(5);/可以连续输出o它们的功能相同。26北京大学程序设计实习课程流操纵算子o流格式操纵算子setioflags nsetiosflags(ios:fixed)用定点方式表示实数nseiosflags(ios:scientific)用指数方式表示实数osetiosflags(ios:fixed)与seiosflags(ios:scientific)都可以和setprecision(n)合用,其效果分别为:控制小数点右边的数字个数,控制指数表示法的小数位数。n在用浮点表示的输出中,setprecision(n)表示有效位数。n在用定点表
14、示的输出中,setprecision(n)表示小数位数。n在用指数形式输出时,setprecision(n)表示小数位数。n小数位数截短显示时,进行4舍5入处理。o左右对齐输出可用setiosflags(ios:left)和setiosflags(ios:right)实现。o强制显示小数点和符号可用setiosflags(ios:showpoint)和setiosflags(ios:showpos)实现。27北京大学程序设计实习课程流操纵算子o浮点数的精度(precision,setprecision)double x=12.3456789,y=12.34;cout setiosflags(i
15、os:fixed)setprecision(6)x endl y endl;o输出为:12.345679 /小数点后有6位 12.34000028北京大学程序设计实习课程流操纵算子o浮点数的精度(precision,setprecision)double x=12.3456789,y=12.34;long z=1234567cout setprecision(6)x endl y endl z setw(5);或者 cin.width(5);cout string)90 cout.width(w+);cout string string)cout.width(w+);cout string s
16、tring;567890 cout string string;cout string string;5678 cout string string;cout string endl;(输出具有同样的性质)34北京大学程序设计实习课程流操纵算子o 用户自定义的流操纵算子ostream&tab(ostream&output)return output t;cout “aa”tab “bb”endl;输出:aa bb35北京大学程序设计实习课程流的错误状态o当流中发生格式错误时,设置failbito当发生导致数据丢失错误时,设置badbito如果eofbit、failbit、badbit都没有设置
17、,则设置goodbito成员函数rdstate返回流的错误状态。o成员函数clear把一个流的状态恢复为“好”,如:cin.clear(),清除cin,并为流设置goodbit。oeof():判断流是否到文件尾36北京大学程序设计实习课程流格式状态o自己阅读 V2版的11.7(V5版的15.7),学会设置流格式状态37北京大学程序设计实习课程内容提要o输入输出流o文件操作o作业38北京大学程序设计实习课程文件操作o数据的层次o文件和流o建立顺序文件o文件的读写指针o有格式读写o无格式读写39北京大学程序设计实习课程数据的层次o位 bito字节 byteo域/记录 Field/Record例如:
18、学生记录 int ID;char name10;int age;int rank10;o我们将所有记录顺序地写入一个文件,称为顺序文件。40北京大学程序设计实习课程文件和流o可以将顺序文件看作一个有限字符构成的顺序字符流,然后象对cin,cout 一样的读写。回顾一下输入输出流类的结构层次:iosistreamostreamifstreamiostreamofstreamfstream41北京大学程序设计实习课程建立顺序文件o#include /包含头文件oofstream outFile(“clients.dat”,ios:out|ios:binary);/打开文件nofstream 是 f
19、stream中定义的类noutFile 是我们定义的ofstream类的对象n“clients.dat”是将要建立的文件的文件名nios:out 是打开并建立文件的选项p ios:out 输出到文件,删除原有内容p ios:app 输出到文件,保留原有内容,总是在尾部添加p ios:ate 输出到文件,保留原有内容,可以在文件任意位置添加 nios:binary 以二进制文件格式打开文件42北京大学程序设计实习课程建立顺序文件o也可以先创建ofstream对象,再用 open函数打开 ofstream fout;fout.open(test.out,ios:out|ios:binary);o判
20、断打开是否成功:if(!fout)cerr “File open error!”x y;fout x “y endl;o说明:n字符文件的读写本质是将所有类型转为字符串,再将字符串转成各种类型的数据。n所以写出来的是文本格式的文件,可以在记事本中阅读。n因为文件流也是流,所以前面讲过的流的成员函数和流操作算子也同样适用于文件流。47北京大学程序设计实习课程二进制文件读写int x=10;fout.seekp(20,ios:beg);fout.write(reinterpret_cast(&x),sizeof(int);fin.seekg(0,ios:beg);fin.read(reinterp
21、ret_cast(&x),sizeof(int);o二进制文件读写,直接写二进制数据,记事本看未必正确。reinterpret_cast(a)任何指针都可以转换成其它类型的指针,T必须是一个指针、引用、算术类型、指向函数的指针或指向一个类成员的指针。表达式reinterpret_cast(a)能够用于诸如能够用于诸如char*到到int*。48北京大学程序设计实习课程显式关闭文件 ifstream fin(“test.dat”,ios:in);fin.close();ofstream fout(“test.dat”,ios:out);fout.close();49北京大学程序设计实习课程获得文
22、件长度ofstream fout(1.txt,ios:out);char a100000;fout.write(reinterpret_cast(a),100000);fout.close();ifstream fin(1.txt,ios:in);fin.read(reinterpret_cast(a),100000);fin.seekg(0,ios:end);long b=fin.tellg();cout b settings-debug-program arguments51北京大学程序设计实习课程命令行参数int main(int argc,char*argv)cout argc end
23、l;for(int i=0;iargc;i+)cout argvi endl;o第一个参数为命令本身,第二个以后为参数52北京大学程序设计实习课程文件目录操作odir -列文件及子目录ocd -当前目录转换omkdir -创建目录o.目录 -当前目录o.目录 -父目录53北京大学程序设计实习课程在程序中得到某个路径下的文件#include HANDLE f1;/句炳WIN32_FIND_DATA fData;/存储文件信息f1=FindFirstFile(e:/teaching/*,&fData);cout fData.cFileName endl;if(fData.dwFileAttribu
24、tes&FILE_ATTRIBUTE_DIRECTORY)=FILE_ATTRIBUTE_DIRECTORY)cout directiory endl;else cout file endl;54北京大学程序设计实习课程在程序中得到某个路径下的文件while(FindNextFile(f1,&fData)cout fData.cFileName endl;if(fData.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)=FILE_ATTRIBUTE_DIRECTORY)cout directiory endl;else cout file 100 pixe
25、l=0 else pixel=2558.创建新文件 9.如果创建失败,释放内存,处理创建失败,退出10.将新数组写进新文件11.释放动态数组12.关闭新文件13.程序结束57北京大学程序设计实习课程内容提要o输入输出流o文件操作o作业58北京大学程序设计实习课程作业o书上:阅读V2版的11.7(或V5版的15.7)o完成练习 V2版的11.12(或V5版的15.12)o几何形体练习3n以几何形体练习2为基础n在基类中加两个虚函数setfromfile(),printtofile()分别用于文件读写,文件统一后缀.geo,在输入文件名时不必输入。向文件输出时注意在每个输出后要输出 或n,否则从文
26、件输入时会出错。从文件输入时,只能屏幕输出,输出结果是按周长大小排序的。而从键盘输入时可以选择是屏幕输出还是文件输出,但都是按面积大小排序的。这点区别请注意。o文件压缩,题目描述放在作业网页上。可以迟些(1-2周)交这个作业。59北京大学程序设计实习课程强制类型转换运算符ostatic_cast(a)n将地址a转换成类型T,T和a必须是指针、引用、算术类型或枚举类型。n表达式static_cast(a),a的值转换为模板中指定的类型T。在运行时转换过程中,不进行类型检查来确保转换的安全性。class B .;class D:public B .;void f(B*pb,D*pd)D*pd2=s
27、tatic_cast(pb);/不安全,pb可能只是B的指针 B*pb2=static_cast(pd);/安全的 .60北京大学程序设计实习课程强制类型转换运算符odynamic_cast(a)n完成类层次结构中的提升。T必须是一个指针、引用或无类型的指针。a必须是决定一个指针或引用的表达式。n表达式dynamic_cast(a)将a值转换为类型为T的对象指针。如果类型T不是a的某个基类型,该操作将返回一个空指针。classA.;classB.;voidf()A*pa=newA;B*pb=newB;void*pv=dynamic_cast(pa);/pv现在指向了一个类型为现在指向了一个类型
28、为A的对象的对象 .pv=dynamic_cast(pb);/pv现在指向了一个类型为现在指向了一个类型为B的对象的对象 61北京大学程序设计实习课程强制类型转换运算符oconst_cast(a)n去掉类型中的常量,除了const或不稳定的变址数,T和a必须是相同的类型。n表达式const_cast(a)被用于从一个类中去除以下这些属性:const,volatile,和 _unaligned。classA.;voidf()constA*pa=newA;/const对象 A*pb;/非const对象 /pb=pa;/这里将出错,不能将const对象指针赋值给非const对象 pb=const_c
29、ast(pa);/现在OK了 .62北京大学程序设计实习课程强制类型转换运算符oreinterpret_cast(a)n任何指针都可以转换成其它类型的指针,T必须是一个指针、引用、算术类型、指向函数的指针或指向一个类成员的指针。n表达式reinterpret_cast(a)能够用于诸如char*到 int*,或者One_class*到 Unrelated_class*等类似这样的转换,因此可能是不安全的。classA.;classB.;voidf()A*pa=newA;void*pv=reinterpret_cast(pa);/pv现在指向了一个类型为B的对象,这可能是不安全的.63北京大学程
30、序设计实习课程static_cast和reinterpret_cast区别 o假设你想把一个int转换成double,以便让包含int类型变量的表达式产生出浮点数值的结果。如用C风格的类型转换,你能这样写:n int firstNumber,secondNumber;double result =(double)firstNumber)/secondNumber;n如果用上述新的类型转换方法,你应该这样写:double result =static_cast(firstNumber)/secondNumber;这样的类型转换不论是对人工还是对程序都很容易识别。oreinterpret_casts的最普通的用途就是在函数指针类型之间进行转换。其的转换结果几乎都是执行期定义(implementation-defined)。因此,使用reinterpret_casts的代码很难移植。ntypedef void (*FuncPtr)();FuncPtr funcPtrArray10;funcPtrArray0 =&doSomething;/错误!类型不匹配 funcPtrArray0 =reinterpret_cast(&doSomething);64