C++面向对象程序设计计算机与信息学院罗宪第六章 模板本章主要内容:
模板的概念
函数模板
类模板第一节 模板的概念一、问题的提出:
C++语言是一种强类型语言,因此象求二个数的最大值函数时,不同类型的数据需要用重载的方式实现。
如,int max(int x,int y)
{ return x>y?x:y;}
float max(float x,float y)
{ return x>y?x:y;}
double max(double x,double y)
{ return x>y?x:y;}
三个函数的实现方法是相同的,只不过数据类型不一样。
问题,能否使这一类问题只写一段代码来实现?
解决的办法,采用模板实现第一节 模板的概念二、模板的概念
例 【 6.1】 用函数模板实现不同类型的二个数最大值的计算。
#include<iostream.h>
#include<string.h>
template <class T>
T max(T x,T y)
{return x>y?x:y;}
void main()
{int i1=10,i2=20;
float f1=30.5,f2=13.9;
double d1=48.255,d2=36.358;
char c1='A',c2='a';
cout <<"the max of i1,i2 is:"<<max(i1,i2)<<endl;
cout <<"the max of f1,f2 is:"<<max(f1,f2)<<endl;
cout <<"the max of d1,d2 is:"<<max(d1,d2)<<endl;
cout <<"the max of c1,c2 is:"<<max(c1,c2)<<endl;
}
第一节 模板的概念
模板 —— 实现代码重用的一种工具 —— 实现类型参数化:即把类型定义为一种参数(模板的实质)。
三、模板的分类
函数模板
类模板。 模 板(函数模板、类模板)
模板函数对 象模板类实例化 实例化实例化第二节 函数模板(教材① P316-327)
一、函数模板的定义
template<class T1,class T2,… >
返回类型 函数名(形参表)
{ 函数体 }
其中:
template<class T1,class T2,… >为模板函数的声明
class T1,class T2,… 为模板形参 —— T1,T2为虚拟类型参数。
可把模板形参改为,typename T1,typename T2,…
第二节 函数模板(教材① P316-327)
例 【 6.2】 定义一个函数模板 swap( ),使之能实现二个整数的交换、二个双精度数的交换、二个点( point
类)的交换。( point类的定义在 hhpoint.h中)
#include<iostream.h>
#include"hhpoint.h"
//template <typename T> //模板函数声明
template <class T> //模板函数声明
void swap(T &a,T &b)
{ T temp;
temp=a;a=b;b=temp;
}
第二节 函数模板(教材① P316-327)
void main(void)
{ int i=20,j=30;
double x=80.5,y=92.6;
point p1(40,50),p2(70,80);
swap(i,j);//将模板函数实例化为整型数据交换
cout<<"\ni="<<i<<" j="<<j<<endl;
swap(x,y);//将模板函数实例化为双精度型数据交换
cout<<"\nx="<<x<<" y="<<y<<endl;
swap(p1,p2);//将模板函数实例化为 point类的数据交换
cout<<"\np1:";p1.print();
cout<<"\np2:";p2.print();
}
第二节 函数模板(教材① P316-327)
二、模板函数的实例化
模板函数是在调用时根据实参的数据类型实例化的:
swap(i,j);—— 或 swap<int>(i,j);—— 实参为
int型 —— 实例化为 swap(int &a,int &b)
swap(x,y);—— 或 swap<double>(x,y);—— 实参为 double型 —— 实例化为
swap(double &a,double &b)
swap(p1,p2); —— 或 swap<point>(p1,p2);—
— 实参为 point型 —— 实例化为
swap(point &a,point &b)
第二节 函数模板(教材① P316-327)
函数模板
swap(T
&a,T&b)
模板函数
int i,j;
swap(i,j);
模板函数
double x,y;
swap(x,y);
模板函数
point p1,p2;
swap(p1,p2);
第二节 函数模板(教材① P316-327)
模板函数中可含常规参数 (即基本数据类型参数 )—
— P321例 6.2(读程序)
例 【 6.3】 函数模板的应用实例( P323—— e603)
三、模板参数的调用及模板实参的缺省
调用格式:
模板函数名 <模板实参表 >(实参表);
通常模板实参均可缺省;
不能缺省的情况,P324-326
第三节 类模板(教材① P327-335)
一、类模板的概念
如果有多个类,其数据成员、成员函数相同,而只是某些数据成员的类型不同,可用类模板的方法处理。
例 【 6.4】 对不同数据类型的数组进行输入、输出、求最大值、排序处理。( e604.cpp)
第三节 类模板(教材① P327-335)
#include <iostream.h>
const int size=50;
template <class T>
class array
{ T x[size];
public:
array()
{int i;
for(i=0;i<size;i++)
x[i]=0;
}
void input(int n)
{int i;
for (i=0;i<n;i++)
{cout<<"x["<<i<<"]=";
cin>>x[i];
}
}
void print(int n)
{int i;
for(i=0;i<n;i++)
cout <<x[i]<<" ";
cout<<endl;
}
T max(int n);
void sort(int n);
};
第三节 类模板(教材① P327-335)
template <class T>
T array<T>:,max(int n)
{ T m;
m=x[0];
int i;
for(i=1;i<n;i++)
if (m<x[i]) m=x[i];
return m;
}
template <class T>
void array<T>:,sort(int n)
{ int i,j;
T t;
for(i=0;i<n-1;i++)
for(j=i+1;j<n;j++)
if(x[i]<x[j])
{t=x[i];x[i]=x[j];x[j]=t;}
}
第三节 类模板(教材① P327-335)
void main()
{ int n;
array <int> ob1;
cout<<"n=";cin>>n;
cout<<"integer:\n";
ob1.input(n);ob1.print(n);
cout<<"max="<<ob1.max(n)<<endl;
ob1.sort(n);
cout<<"sort:";ob1.print(n);
cout<<"\nfloat:\n";
array <float> ob2;
ob2.input(n);ob2.print(n);
cout<<"max="<<ob2.max(n)<<endl;
ob2.sort(n);
cout<<"sort:";ob2.print(n);
}
第三节 类模板(教材① P327-335)
二、类模板的定义
1、类模板的定义
格式,template<class T1,class T2,… >
class 类模板名
{ 类体 }
2、成员函数的定义
在类体中定义(即定义为内置函数):同普通类成员函数的定义。
在类体外定义
template<class T1,class T2,… >
返回类型 类模板名 <模板形参表 >::函数名(形参表)
{ 函数体 }
第三节 类模板(教材① P327-335)
三、类模板应用举例
例 【 6.5】 定义一个堆栈模板类( tmpstack.h)
堆栈是一种常见的数据结构 —— 先进后出(后进先出);
堆栈通常用数组实现;
堆栈的主要操作有:
压栈操作:将数据压入栈顶( push),栈顶上移;
出栈操作:取栈顶元素( pop),栈顶下移;
取栈顶元素;
栈初始化;
判断栈是否为空;
判断栈是否填满。
第三节 类模板(教材① P327-335)
#include<stdlib.h>
const int maxstacksize=80;//数组元素:堆栈数据的最大个数
template <class T> //定义一个模板(类模板)
class stack //statck为一个堆栈类模板
{ private:
T stklist[maxstacksize];//堆栈数组:存放数据项
int top; //表示栈顶
public:
stack(void);
void push(const T &item);//压栈操作
T pop(void); //出栈操作
T peek(void); //取栈顶数据
int stkempty(void); //堆栈是否为空
int stkfull(void); //堆栈是否满
void clearstk(void); //栈初始化,栈清空
};
第三节 类模板(教材① P327-335)
template <class T>
stack<T>::stack(void)
{ top=-1;} //栈顶初始化为 -1
template <class T>
void stack<T>::push(const T &item) //压栈操作
{ if(top==maxstacksize-1)
{ cerr<<"堆栈已满,终止程序 !\n";
exit(1);
}
top++; //栈顶增值 1
stklist[top]=item; //栈顶元素赋值
}
第三节 类模板(教材① P327-335)
template <class T>T stack<T>::pop(void) //出栈操作
{ T temp;if(top==-1)
exit(1);
}temp=stklist[top]; //取栈顶元素
{ cerr<<"堆栈已满,终止程序 !\n";top--; //栈顶减值 1
return temp;
}template <class T>
T stack<T>::peek(void){ if(top==-1)
{ cerr<<"堆栈已空,终止程序 !\n";
return;}
return stklist[top];}
第三节 类模板(教材① P327-335)
template <class T>
int stack<T>::stkempty(void) //检测堆栈是否为空
{ if (top==-1) return 1;
else return 0;
}
template <class T>
int stack<T>::stkfull(void) //检测堆栈是否已满
{ if(top=maxstacksize-1) return 1;
else return 0;
}
template <class T>
void stack<T>::clearstk(void) //堆栈初始化
{ top=-1;}
第三节 类模板(教材① P327-335)
验证:
输入字符串,按逆序输出( e6051.cpp)。
#include<iostream.h>#include<string.h>
#include"tmpstack.h"void main()
{ stack <char>ss;//定义类模板对象 ss,其模板参数 T实例化为 char型//即,创建了一个字符堆栈
char name[81],reverse[81];int i;
cout<<"输入一个字符串,";cin>>name;
for(i=0;i<strlen(name);i++)ss.push(name[i]); //将 name[i]压入堆栈,即压栈操作
for(i=0;i<strlen(name);i++)reverse[i]=ss.pop();//将栈顶元素赋值给 reverse[i]:
//即出栈操作reverse[i]='\0';
cout<<reverse<<endl;}
第三节 类模板(教材① P327-335)
将一个十进制整数转换为某一种进制数。
#include<iostream.h>
#include"tmpstack.h"
void multiRadixOutput(int num,int r)
{ stack <int> s;
int num1;
do
{ num1=num%r;//num1表示除基后的余数,除基取余
num=num/r;
s.push(num1);//将余数压入堆栈:压栈操作
} while(num!=0); //直到商为 0结束循环
while(!s.stkempty()) //栈不为空则循环
{ cout<<s.pop();} //输出栈顶元素:出栈操作
}
第三节 类模板(教材① P327-335)
void main(void)
{ int num,r;
cout<<"请输入一个整数,";cin>>num;
cout<<"请输入转换后的进制基数,";cin>>r;
cout<<"转换后的结果为,";
multiRadixOutput(num,r);
cout<<endl;
}
四、类模板的实例化( P331图 6.2)
五、类模板的继承( P332-335)
模板的概念
函数模板
类模板第一节 模板的概念一、问题的提出:
C++语言是一种强类型语言,因此象求二个数的最大值函数时,不同类型的数据需要用重载的方式实现。
如,int max(int x,int y)
{ return x>y?x:y;}
float max(float x,float y)
{ return x>y?x:y;}
double max(double x,double y)
{ return x>y?x:y;}
三个函数的实现方法是相同的,只不过数据类型不一样。
问题,能否使这一类问题只写一段代码来实现?
解决的办法,采用模板实现第一节 模板的概念二、模板的概念
例 【 6.1】 用函数模板实现不同类型的二个数最大值的计算。
#include<iostream.h>
#include<string.h>
template <class T>
T max(T x,T y)
{return x>y?x:y;}
void main()
{int i1=10,i2=20;
float f1=30.5,f2=13.9;
double d1=48.255,d2=36.358;
char c1='A',c2='a';
cout <<"the max of i1,i2 is:"<<max(i1,i2)<<endl;
cout <<"the max of f1,f2 is:"<<max(f1,f2)<<endl;
cout <<"the max of d1,d2 is:"<<max(d1,d2)<<endl;
cout <<"the max of c1,c2 is:"<<max(c1,c2)<<endl;
}
第一节 模板的概念
模板 —— 实现代码重用的一种工具 —— 实现类型参数化:即把类型定义为一种参数(模板的实质)。
三、模板的分类
函数模板
类模板。 模 板(函数模板、类模板)
模板函数对 象模板类实例化 实例化实例化第二节 函数模板(教材① P316-327)
一、函数模板的定义
template<class T1,class T2,… >
返回类型 函数名(形参表)
{ 函数体 }
其中:
template<class T1,class T2,… >为模板函数的声明
class T1,class T2,… 为模板形参 —— T1,T2为虚拟类型参数。
可把模板形参改为,typename T1,typename T2,…
第二节 函数模板(教材① P316-327)
例 【 6.2】 定义一个函数模板 swap( ),使之能实现二个整数的交换、二个双精度数的交换、二个点( point
类)的交换。( point类的定义在 hhpoint.h中)
#include<iostream.h>
#include"hhpoint.h"
//template <typename T> //模板函数声明
template <class T> //模板函数声明
void swap(T &a,T &b)
{ T temp;
temp=a;a=b;b=temp;
}
第二节 函数模板(教材① P316-327)
void main(void)
{ int i=20,j=30;
double x=80.5,y=92.6;
point p1(40,50),p2(70,80);
swap(i,j);//将模板函数实例化为整型数据交换
cout<<"\ni="<<i<<" j="<<j<<endl;
swap(x,y);//将模板函数实例化为双精度型数据交换
cout<<"\nx="<<x<<" y="<<y<<endl;
swap(p1,p2);//将模板函数实例化为 point类的数据交换
cout<<"\np1:";p1.print();
cout<<"\np2:";p2.print();
}
第二节 函数模板(教材① P316-327)
二、模板函数的实例化
模板函数是在调用时根据实参的数据类型实例化的:
swap(i,j);—— 或 swap<int>(i,j);—— 实参为
int型 —— 实例化为 swap(int &a,int &b)
swap(x,y);—— 或 swap<double>(x,y);—— 实参为 double型 —— 实例化为
swap(double &a,double &b)
swap(p1,p2); —— 或 swap<point>(p1,p2);—
— 实参为 point型 —— 实例化为
swap(point &a,point &b)
第二节 函数模板(教材① P316-327)
函数模板
swap(T
&a,T&b)
模板函数
int i,j;
swap(i,j);
模板函数
double x,y;
swap(x,y);
模板函数
point p1,p2;
swap(p1,p2);
第二节 函数模板(教材① P316-327)
模板函数中可含常规参数 (即基本数据类型参数 )—
— P321例 6.2(读程序)
例 【 6.3】 函数模板的应用实例( P323—— e603)
三、模板参数的调用及模板实参的缺省
调用格式:
模板函数名 <模板实参表 >(实参表);
通常模板实参均可缺省;
不能缺省的情况,P324-326
第三节 类模板(教材① P327-335)
一、类模板的概念
如果有多个类,其数据成员、成员函数相同,而只是某些数据成员的类型不同,可用类模板的方法处理。
例 【 6.4】 对不同数据类型的数组进行输入、输出、求最大值、排序处理。( e604.cpp)
第三节 类模板(教材① P327-335)
#include <iostream.h>
const int size=50;
template <class T>
class array
{ T x[size];
public:
array()
{int i;
for(i=0;i<size;i++)
x[i]=0;
}
void input(int n)
{int i;
for (i=0;i<n;i++)
{cout<<"x["<<i<<"]=";
cin>>x[i];
}
}
void print(int n)
{int i;
for(i=0;i<n;i++)
cout <<x[i]<<" ";
cout<<endl;
}
T max(int n);
void sort(int n);
};
第三节 类模板(教材① P327-335)
template <class T>
T array<T>:,max(int n)
{ T m;
m=x[0];
int i;
for(i=1;i<n;i++)
if (m<x[i]) m=x[i];
return m;
}
template <class T>
void array<T>:,sort(int n)
{ int i,j;
T t;
for(i=0;i<n-1;i++)
for(j=i+1;j<n;j++)
if(x[i]<x[j])
{t=x[i];x[i]=x[j];x[j]=t;}
}
第三节 类模板(教材① P327-335)
void main()
{ int n;
array <int> ob1;
cout<<"n=";cin>>n;
cout<<"integer:\n";
ob1.input(n);ob1.print(n);
cout<<"max="<<ob1.max(n)<<endl;
ob1.sort(n);
cout<<"sort:";ob1.print(n);
cout<<"\nfloat:\n";
array <float> ob2;
ob2.input(n);ob2.print(n);
cout<<"max="<<ob2.max(n)<<endl;
ob2.sort(n);
cout<<"sort:";ob2.print(n);
}
第三节 类模板(教材① P327-335)
二、类模板的定义
1、类模板的定义
格式,template<class T1,class T2,… >
class 类模板名
{ 类体 }
2、成员函数的定义
在类体中定义(即定义为内置函数):同普通类成员函数的定义。
在类体外定义
template<class T1,class T2,… >
返回类型 类模板名 <模板形参表 >::函数名(形参表)
{ 函数体 }
第三节 类模板(教材① P327-335)
三、类模板应用举例
例 【 6.5】 定义一个堆栈模板类( tmpstack.h)
堆栈是一种常见的数据结构 —— 先进后出(后进先出);
堆栈通常用数组实现;
堆栈的主要操作有:
压栈操作:将数据压入栈顶( push),栈顶上移;
出栈操作:取栈顶元素( pop),栈顶下移;
取栈顶元素;
栈初始化;
判断栈是否为空;
判断栈是否填满。
第三节 类模板(教材① P327-335)
#include<stdlib.h>
const int maxstacksize=80;//数组元素:堆栈数据的最大个数
template <class T> //定义一个模板(类模板)
class stack //statck为一个堆栈类模板
{ private:
T stklist[maxstacksize];//堆栈数组:存放数据项
int top; //表示栈顶
public:
stack(void);
void push(const T &item);//压栈操作
T pop(void); //出栈操作
T peek(void); //取栈顶数据
int stkempty(void); //堆栈是否为空
int stkfull(void); //堆栈是否满
void clearstk(void); //栈初始化,栈清空
};
第三节 类模板(教材① P327-335)
template <class T>
stack<T>::stack(void)
{ top=-1;} //栈顶初始化为 -1
template <class T>
void stack<T>::push(const T &item) //压栈操作
{ if(top==maxstacksize-1)
{ cerr<<"堆栈已满,终止程序 !\n";
exit(1);
}
top++; //栈顶增值 1
stklist[top]=item; //栈顶元素赋值
}
第三节 类模板(教材① P327-335)
template <class T>T stack<T>::pop(void) //出栈操作
{ T temp;if(top==-1)
exit(1);
}temp=stklist[top]; //取栈顶元素
{ cerr<<"堆栈已满,终止程序 !\n";top--; //栈顶减值 1
return temp;
}template <class T>
T stack<T>::peek(void){ if(top==-1)
{ cerr<<"堆栈已空,终止程序 !\n";
return;}
return stklist[top];}
第三节 类模板(教材① P327-335)
template <class T>
int stack<T>::stkempty(void) //检测堆栈是否为空
{ if (top==-1) return 1;
else return 0;
}
template <class T>
int stack<T>::stkfull(void) //检测堆栈是否已满
{ if(top=maxstacksize-1) return 1;
else return 0;
}
template <class T>
void stack<T>::clearstk(void) //堆栈初始化
{ top=-1;}
第三节 类模板(教材① P327-335)
验证:
输入字符串,按逆序输出( e6051.cpp)。
#include<iostream.h>#include<string.h>
#include"tmpstack.h"void main()
{ stack <char>ss;//定义类模板对象 ss,其模板参数 T实例化为 char型//即,创建了一个字符堆栈
char name[81],reverse[81];int i;
cout<<"输入一个字符串,";cin>>name;
for(i=0;i<strlen(name);i++)ss.push(name[i]); //将 name[i]压入堆栈,即压栈操作
for(i=0;i<strlen(name);i++)reverse[i]=ss.pop();//将栈顶元素赋值给 reverse[i]:
//即出栈操作reverse[i]='\0';
cout<<reverse<<endl;}
第三节 类模板(教材① P327-335)
将一个十进制整数转换为某一种进制数。
#include<iostream.h>
#include"tmpstack.h"
void multiRadixOutput(int num,int r)
{ stack <int> s;
int num1;
do
{ num1=num%r;//num1表示除基后的余数,除基取余
num=num/r;
s.push(num1);//将余数压入堆栈:压栈操作
} while(num!=0); //直到商为 0结束循环
while(!s.stkempty()) //栈不为空则循环
{ cout<<s.pop();} //输出栈顶元素:出栈操作
}
第三节 类模板(教材① P327-335)
void main(void)
{ int num,r;
cout<<"请输入一个整数,";cin>>num;
cout<<"请输入转换后的进制基数,";cin>>r;
cout<<"转换后的结果为,";
multiRadixOutput(num,r);
cout<<endl;
}
四、类模板的实例化( P331图 6.2)
五、类模板的继承( P332-335)