1、模模 板板(函数模板、类模板)(函数模板、类模板)模板函数模板函数对对 象象模板类模板类实例化实例化 实例化实例化实例化实例化图 9.1 模板分类实验九 模板及应用 函数模板一、实验目的1理解模板的概念及实质,熟悉 C+模板的分类;2掌握函数模板的定义方法及实例化方法,掌握函数模板的应用。二、实验学时课内实验:2 课时 课外练习:2 课时三 本实验涉及的新知识 模板的概念及分类1模板的概念在 C+中,模板是实现代码重用的一种工具,其实质是实现数据类型参数化。也就是说,把数据类型定义为一种参数。2模板的分类C+中的模板分为函数模板及类模板。函数模板的实例化称为模板函数,类模板的实例化称模板类。如
2、图 9.1 所示。 函数模板的定义1格式template 返回类型 函数名(形参表) 函数体 2说明 template 为模板函数的声明; class T1,class T2,为模板形参,即 T1、T2 为虚拟类型参数;可把模板形参改为:typename T1,typename T2, 模板函数的实例化模板函数是在调用时根据实参的数据类型实例化。1格式函数名(实参表)2说明 模板实参表通常可以缺省,这时模板函数与一般函数的调用相同。即上面的格式可变为:函数名(实参表) 有些情况下,模板实参表不能省略: 含有“常规参数”的函数模板,在实例化为模板函数时,必须给出。 当实例化模板函数的实参表中出现
3、模棱两可的数据类型时,必须给出。 当要明确模板函数的返回值时,必须给出。四、实验内容1 验证及认知实验按要求调试下列程序,并回答相关问题。程序 1(exp_901.cpp)#includeint max(int x,int y) return xy?x:y;float max(float x,float y) return xy?x:y;double max(double x,double y) return xy?x:y;char max(char x,char y) return xy?x:y;void main()int i1=10,i2=20;float f1=30.5,f2=13.9
4、;double d1=48.255,d2=36.358;char c1=A,c2=a;cout T max(T x,T y)return xy?x:y;再重新编译运行程序。 知识应用实验1分析下列程序,写出程序的输出结果,再上机运行程序验证其正确性,如果不正确,请认真分析出错原因。程序 2(exp_902.cpp)#include2using namespace std;templatevoid func(T a,int n) T t; for(int i=0;i#include“hhpoint.h“template /模板函数声明:实现两个数据的交换void swap( (2) ) (3)
5、;temp=a;a=b;b=temp;void main(void) int i=20,j=30;double x=80.5,y=92.6;point p1(40,50),p2(70,80);(4); /将模板函数实例化为整型数据交换cout class 类模板名 类体 2类模板中的成员函数的定义 在类体中定义(即定义为内置函数)与普通类的成员函数定义相同。 在类体外定义格式template返回类型 类模板名:函数名(形参表) 函数体 类模板的实例化类模板是在定义对象时实例化的。格式为:类模板名 对象名表;四、实验内容 验证及认知实验按要求调试下列程序,并回答相关问题。程序 1(exp_100
6、1.cpp)#includetemplate class point private:A x,y;public:point(void) x=0;y=0;5point(A a,A b) x=a ; y=b; point(const point y=ob.y;void set_point(A a,A b);A read_x(void);A read_y(void);void move(A a,A b);void print(void);template void point :set_point(A a,A b)x=a ; y=b; template A point :read_x(void) r
7、eturn x;template A point:read_y(void) return y;template void point:move (A a,A b) x+=a;y+=b;template void point:print(void) cout p1(20,30);p1.print();p1.move(5,5); p1.print();运行程序的输出结果为: 程序中的“point p1(20,30);”的作用是 ; 在 main()中加入下列语句:point p2(20.55,30.65);p2.print();p2.move(5.5,10.5); p2.print();运行程序的
8、输出结果为:6 程序中的“point p2(20.55,30.65); ”的作用是 。 知识应用实验1分析下列程序,写出程序的输出结果,再上机运行程序验证其正确性,如果不正确,请认真分析出错原因。#include const int size=50;template class array T xsize;public:array()int i;for(i=0;ixi;void print(int n)int i;for(i=0;iT array: max(int n) T m;m=x0;int i;for(i=1;i运行程序,输入 n 的值为 5,再分别输入:21、25、18、32、59 时
9、,你分析的程序输出结果为:程序的实际输出结果是:当输入:18.2、12.8、19.5、23.2、17.8 时,你分析的程序输出结果为:程序的实际输出结果是:7void array: sort(int n) int i,j;T t;for(i=0;i ob1;coutn;cout ob2;ob2.input(n);ob2.print(n);coutconst int maxstacksize=80;/数组元素:堆栈数据的最大个数template /定义一个模板(类模板)class stack /statck 为一个堆栈类模板 private:T stklistmaxstacksize;/堆栈数组
10、:存放数据项int top; /表示栈顶public:stack(void);void push(const T /压栈操作T pop(void); /出栈操作T peek(void); /取栈顶数据int stkempty(void); /堆栈是否为空int stkfull(void); /堆栈是否满void clearstk(void); /栈初始化: 栈清空;8template stack:stack(void) top=-1; /栈顶初始化为-1template void stack:push(const T if(top=-1) cerr /取栈顶数据T stack:peek(voi
11、d) if(top=-1) cerrint stack:stkempty(void) /检测堆栈是否为空 if ( (6) ) return 1;else return 0;template int stack:stkfull(void) /检测堆栈是否已满 if( (7) ) return 1;else return 0;9template void stack:clearstk(void) /堆栈初始化 top=(8) ; 问题:程序中(1)处应改为 , (2)处应改为 (3)处应改为 , (4)处应改为 (5)处应改为 , (6)处应改为 (7)处应改为 , (8)处应改为 /exp_1
12、003.cpp:输入一个字符串,再逆序输出#include#include#include“tmpstack.h“void main() stack ss;/定义类模板对象 ss,其模板参数 T 实例化为 char 型/即:创建了一个字符堆栈char name81,reverse81;int i;coutname;for(i=0;i#include“tmpstack.h“void multiRadixOutput(int num,int r) (11) s; /定义一个整数堆栈模板类对象“s”int num1;do num1=num%r;/num1 表示除基后的余数 :除基取余num=num/
13、r;10(12); /将余数压入堆栈:压栈操作 while(num!=0); /直到商为 0 结束循环int a;while( (13) ) /栈不为空则循环 a= (14) ; /取栈顶元素并出栈if(anum;coutr;cout”的重载方法3熟悉用 ios_base 类成员函数进行格式控制的方法,掌握其应用;4熟悉用操作符进行输入输出格式控制的方法,掌握其应用。二、实验学时课内实验:2 课时 课外实验:2 课时三 本实验涉及的新知识 流的概念及输入输出流对象1流的概念 在计算机中,数据从内存的一个地址移动到另一个地址称为数据流动,简称流(stream) ;其操作称为流操作。 流操作是通过
14、缓冲区(buffer)机制实现的。在 C+中的主要流操作有:从文件中读职数据:文件缓冲区内存将数据写入文件:内存缓冲区文件在 C+中,把输入设备(如键盘 KB) 、输出设备(如显示器 CRT、打印机 PRT)看成一种文件,称设备文件。因此,输入输出操作与文件的操作相似。2C+的主要流对象C+中输入输出操作通过调用标准流库实现。主要流对象有: cin :与标准输入设备(即键盘)相关联 cout :与标准输出设备(即显示器)相关联 cerr :与标准错误输出设备(默认为显示器)相关联(非缓冲方式) clog:与标准错误输出设备(默认为显示器)相关联(缓冲方式) 输出流1输出流(ostream)类中
15、的主要成员函数 put( ) 函数函数原型声明:ostream 作用:可用作为二进制数据(字节)或单个字符输出。调用格式:cout.put(字符) write( )函数函数原型声明:ostream (主要熟悉:left、right、dec、oct 、hex、showpoint、fixed)特点:分别使不同的标志位为 1(用二进制表示时) 。标志字的表示:可用位或运算符(“|” )组合多个状态标志位。如:设置标志字表示在输入时用十进制并跳过空白,标志字为: 0000 0000 0001 0001即:skipws|dec 用于输入输出格式控制的成员函数 成员函数如下表函数原型 功 能 long i
16、os_base:setf(long flags); 设置状态标志 flags long ios _base :unsetf(long flags); 清除状态标志并返回清除前的标志 long ios _base :flags( ); 测试状态标志 long ios _base : flags(long flags); 设置标志 flags 并返回设置前标起 int ios _base :width(); 返回当前宽度设置值 int ios _base :width(int w); 设置域宽 w 并返回以前的设置 int ios _base :precision(int p); 设置小数位数,并
17、返回以前的小数位数 char ios:fill( ) 返回当前的填充字符 char ios:fill( char ch) 设置填充字符 ch,返回当前的填充字符 使用方法如下: setf( )格式:流对象.setf(ios:状态标志)功能:设置状态标志 说明:流对象通常是 cin 、cout 等或用户自定义的流对象(下同) 。 unsetf( )格式:流对象.unsetf(ios:状态标志) 14功能:取消状态标志 .width( )格式:流对象.width( 整数 ) 功能:设置域宽并返回以前的设置说明:用 width(int w)设置域宽后,只对紧接着的第一个输出有影响;用 ios:set
18、f(long flags)设置后对后面所有输出都有影响,直到用 ios:unsetf(long flags)取消为止。 precision( )格式:流对象. precision( 整数 ) 功能:设置有效位数(小数位数) ,并返回以前的有效位数(小数位数)未用 ios:setf()函数设置为定点记数或科学记数法前,用 ios: precision(int p)中的 p 表示显示的有效位数;用 ios:setf()函数设置为定点记数或科学记数法后,p 表示小数位数。 fill()格式:流对象. fill( 字符 )功能:设置填充字符 ch,返回当前的填充字符;设置填充字符后,对后面的所有输出内
19、容均有效。 2使用操作符进行输入输出格式控制 使用 ios 类中的成员函数进行输入输出格式控制时,每个函数的调用都需要写一条语句,不能将其嵌入到输入输出语句中。在 C+提供了另一种 I/O 格式控制的方法,即操作符。C+预定义的操作符: dec:以十进制输入输出整型数,用于输入输出 hex:以十六进制输入输出整型数,用于输入输出 oct:以八进制输入输出整型数,用于输入输出 ws 输入时跳过开头的空白符,用于输入 endl 插入一个换行符并刷新输出流,用于输出 ends 插入一个空字符,用以结束一个字符串,用于输出 flush 刷新一个输入流,用于输入 setbase(int n) 把转换基数
20、设置为 n(n 的取值为 0,8,10,16),n 的缺省值为 0(以十进进制形式输出) 。 resetiosflags(long f) 关闭由参数 f 指定的格式标志,用于输入输出 setiosflags(long f) 设置由参数 f 指定的格式标志,用于输入输出 setfill(char c) 设置填充字符 setprecision(int n) 设置数据小数位数,缺省时为 6,用于输入输出 setw(int n) 设置域宽,用于输入输出其中:setiosflags(long f) 、resetiosflags(long f) 中的 long f 为格式标志与前面相同。说明:使用 set
21、w()等,应加头文件 “iomanip.h”(主要熟悉 dec、hex、oct 、 endl、setw(int n) 、setprecision(int n)四、实验内容 验证及认知实验按要求调试下列程序,并回答相关问题。程序 1(exp_1101.cpp)#include15#includeusing namespace std;void main(void) int ch=97;char str=“student“;cout.put(ch)#includeusing namespace std;void main(void) char ch,ch1;char str10=“;coutvoi
22、d main()int a=120,b=250;double x=256.43l,y=130.125;cout.setf(ios:dec|ios:showpos);coutusing namespace std;void main()int a=120,b=250;double x=256.43l,y=130.125;cout.width(10);coutusing namespace std;void main()double x=256.43l,y=130.125;cout.precision(5);/设置有效位数为 5coutusing namespace std;void main()
23、int a=120,b=250;cout.setf(ios:left);cout.width(10);cout.fill(*); cout#include void main() cout using namespace std;class point private:float x,y,z;public :point(float a=0,float b=0,float c=0) x=a;y=b;z=c;friend (1) cout” 、 “格式 2:if(文件流对象) 用成员 fail()函数格式 1:if(文件流对象.fail()格式 2:if(!文件流对象.fail()4文件的关闭格式
24、:文件流对象.close(); 文件的读写1文本文件的读写 读文件格式文件输入流对象.get(char); 写文件格式文件输出流对象.put(char ch);2二进制文件的读写二进制文件的读/写分别用成员函数 read( )、write( ) 实现。21 读二进制文件的格式输入文件流对象.read(char*)void main(void) ifstream f1; f1.open(“d:vcprge301.cpp“); if(!f1) cout #includeusing namespace std;void main(void) ofstream f;/定义文件输出流对象f.open(“
25、d:vcprgtest.txt“);/ f.open(“d:vcprgtest.txt“,ios_base:app);if(!f) cout #include23using namespace std;void main(void) (1) ; /定义文件输入流对象 f1(2) ; /定义文件输出流对象 f2f1.open(“d:vcprge301.cpp“); /以读方式打开文件if( (3) ) cout #include#include“person.h“void main(void) char na11,se3;int y,m,d;person psn;ifstream f1;ofst
26、ream f2;f2.open(“d:vcprgpersonal.dat“,ios:binary|ios:app);if(!f2) coutna;coutse;couty;coutm;coutd;psn.set_person(na,se,y,m,d);f2.write(6);/将 psn 对象写入文件中coutch;f2.close();f1.open(“d:vcprgpersonal.dat“,ios:binary);if(!f1) /或者用 if(f1.fail() cout”实现学生数据的输入/ 输出(输出时各列对整齐) ; 学生数据查询按学号或姓名查询; 程序存放在 exp_1206.cpp 中。五、实验收获与创新1自已拟定一个解决实际问题的题目,综合应用高级语言程序设计 、 面向对象程序设计中的知识,编程实现。要求:至少定义两个类,数据用文件保存。2通过实验一到实验十二,谈谈你对面向对象程序设计的认识。