C template

Shared by: xhch
Categories
Tags
-
Stats
views:
13
posted:
12/6/2012
language:
pages:
26
Document Sample
scope of work template
							第12章 模板
本讲内容提要

   函数模板
       函数模板
       模板函数
       模板实参的省略
   类模板
       类模板的概念与定义
       模板类
       类模板的继承与派生
 请看下面的函数:
void add(int a[],int b[],int size){
      for(int i=0;i<size;i++) b[i]+=a[i];
}


如果不限定数组的类型为整型,则……

void add(float a[],float b[],float size){
      for(int i=0;i<size;i++) b[i]+=a[i];
}
void add(double a[],float b[],double size){
      for(int i=0;i<size;i++) b[i]+=a[i];
}
……
一、函数模板

   函数模板是通过对参数类型进行参数化后,
    获取有相同形式的函数体。
   它是一个通用函数,它可适应一定范围内
    的不同类型对象的操作。
   函数模板将代表着不同类型的一组函数,
    它们都使用相同的代码,这样可以实现代
    码重用,避免重复劳动,又可增强程序的
    安全性。
  1.函数模板

     利用函数模板解决上述问题。
函数模板的定义格式:
template <(参数化类型名表)><类型> <函数名>(<模板参数表>)
  {
    <函数体>
  }
参数化类型名表又称模板参数表,多个表项用逗号分隔。
每个表项称为一个模板参数(模板形参)。格式如下:
class <参数名>
或typename<参数名>
或<类型修饰> <参数名>
add模板可以定义为:
template <class T>
void add(T a[],T b[],int size){
      for(int i=0;i<size;i++) b[i]+=a[i];
}


   其中,“< >”括起部分就是模板的形参表,T是
    一个虚拟类型参数。注意,可以用多个虚拟参数
    构成模板形参表。
   不但普通函数可以声明为函数模板,类的成员函
    数也可以声明为函数模板。
    2.模板函数

      函数模板是模板函数的一个样板,它可以
       生成多个重载的模板函数,这些模板函数
       重用函数体代码。
template <typename T1,typename T2>
void add(T1 a[],T2 b[],int size){
      模板函数是函数模板的一个实例。
    for(int i=0;i<size;i++) b[i]+=a[i];
}     函数模板的实例化(instantiation)
long float x[]={1,2,3,4,5,6},y[]={7,8,9,10,11,12};
add(x,y,6);

void add(float a[],float b[],float size){
for(int i=0;i<size;i++) b[i]+=a[i];
}
#include <iostream.h>
        例12.1:
#include<string.h>
template<class stype> void bubble(stype *item, int count);
          问题:分析程序输出结果。
void main()
{int nums1[]={4,7,2,9,3,7,6,1};
        template<class stype>
 bubble(nums1,8);
        void bubble(stype *item, int count)
 cout<<"The sorted numbers are ";
        {
 for(int i(0);i<8;i++)
              stype bubb;
      cout<<nums1[i]<<" ";
 cout<<endl; for(int i=0;i<=count-1;i++)
                    for(int j=i+1;j<count;j++)
 double nums2[]={2.3,5.3,6.7,3.9,7.2,1.5};
 bubble(nums2,6);         if(item[i]>item[j])
                          {
 cout<<"The sorted numbers are ";
 for(i=0;i<6;i++)               bubb=item[i];
                                item[i]=item[j];
      cout<<nums2[i]<<" ";cout<<endl;}
                                item[j]=bubb;
                          }
        }
3.模板实参的省略

   模板实参的省略是有条件的。
   以下四种情况模板实参不能省略:
       从模板函数实参表获得的信息有矛盾。
       需要获得特定类型的返回值,而不管参数的类
        型如何。
       虚拟类型参数没有出现在模板函数的形参表中。
       函数模板含有常规形参。
从模板函数实参表获得的信息有矛盾。
   例如:
       template<typename T>
       T add(T a,T b){return a+b;}
            若调用函数的语句为:cout<<add(3,5);
                 则编译系统无论是从3还是5所获得的信息都是T对应
                  于int,因此可顺利地生成如下模板函数:int
                  add(int a, int b){return a+b;}
            调用语句变为:
                 cout<<add<int>(3.0,5);
                 其中,紧跟在函数名后的<int>就是模板实参表,
                  此时,编译系统生成如下的模板函数:
                     int add(int a,int b){return a+b;}
需要获得特定类型的返回值,而不管参
数的类型如何。

   例如,
       如果需要add返回一个int型的值,
       那么直接以add<int>(a,b);形式调用即可。
  虚拟类型参数没有出现在模板函数的形
  参表中。

   由于虚拟类型参数没有出现在模板函数的
    形参表中,所以调用时不可能从模板函数
    的实参表中获得相应的信息,因此无法省
    略。
#include<iostream>
using namespace std;
   例12.2 分析程序输出结果。
template<typename T1,typename T2,typename T3>
T2 add(T1 a,T3 b){return a+b;}
void main()
{ 程序运行结果为:
  8    cout<<showpoint;
       cout<<add<double,int>(3,5L)<<endl;
  8.00000
       cout<<add<int,double,long>(3,5L)<<endl;
}
  函数模板含有常规形参。

    当函数模板含有常规形参时,如果常规参
     数的信息无法从模板函数的实参表中获得,
#include<iostream>
      namespace std;
using则在调用时必须显式的给出对应于常规参
template <class T,int rows>
sum(T数的模板实参。
      data[],T &result)
{result=0;
   例12.3 分析程序输出结果。
 for(int i=0;i<rows;i++)
      result+=data[i];}
int main()
{int d[3]={1,2,3};int r;
//此处必须显式给出对应于常规参数的模板实参
 程序运行结果为:
sum<int,3>(d,r);
 sum=6
cout<<"sum="<<r<<endl;
return 0;}
二、类模板

1.为何要引进类模板?
       按不同的方式重用相同的代码
       使代码参数化(通用化),即不受类型和操作
        的影响
   使用类模板所定义的一种类类型,类中的
    某些数据成员和某些成员函数的参数及返
    回值可以选取一定范围内的多种类型,从
    而实现代码重用。
   是一种参数化类型的类,是类的生成器。
讨论引进类模板的必要性
有如下程序:Node是链表的节点类,List为链表类。
class Node {……};
class List{
public:List();
~List();
void Add(Node &);
void Remove(Node &);
Node *Find(Node &);
……
};
//该类的实现部分略……
通用化修改,使用参数T
class List{
public:List();
~List();
void Add(T &);
void Remove(T &);
Node *Find(T &);
……
};
//该类的实现部分略……
2.类模板
(1)类模板的定义
template<模板参数表>
class <类名>
{<类体说明>};
//类体实现
   模板参数表
       class <标识符>
 例如,array.h文件中类模板的定义
(2)用类模板定义对象的格式是:
   <类名><<模板实参表>><对象名>(<构造函数实参表>);
3. 模板类

模板类
 在定义了类模板后,可根据需要生成相应
  的模板类。即,对模板参数,指定具体的
  类型。
       例如,当指定AType 为int型时,生成模板类
        array <int>
   利用模板类创建对象格式如下:
       array <int> a1=10;
      程序运行结果为:
      9 8 7 6 5 4 3 2 1 0
      例12.4:
      22.5 20 17.5 15 12.5 10 7.5 5 2.5 0
      a b c d e f g h i j

        问题:分析程序输出结果。
     void main()
      #include<iostream.h>
    template<class T>
     {      stack T>
  template <class<int> a(10);//模板类stack<int>
      #include<stdlib.h>
    stack<T>::stack(int size)//构造函数
template <class T>
            stack <double> b(10);//模板类stack<double>
      template <class T>
  void stack<T>::push(T i)//入栈
    {
T stack <T>::pop()//出栈 c(10);//模板类stack<char>
  { class stack <char>
            stack
{          stck=new T[size];
            for(int i=0;i<10;i++)a.push(i);
            public:
      { if(tos==length)//满栈
           if(!stck)
            for(i=0;i<10;i++) full.\n";
       if(tos==0) stack(int isb.push(i*2.5);
               cout<<"Stack size);
           {for(i=0;i<10;i++) cout<<a.pop()<<' ';
             cout<<"Stack underflow.\n";
                  ~stack()
         stck[tos]=i;
       tos--;    cout<<"cannot allocate stack.\n";
            cout<<endl;
                  {delete [] stck;}
         tos++;
                 exit(1);
            for(i=0;i<10;i++) cout<<b.pop()<<' ';
       return stck[tos];
                  void push(T i);
  }
}          }cout<<endl;
                  T pop();
           length=size;//栈长度c.push((char)'j'-i);
            for(i=0;i<10;i++)
            private:
           tos=0; int tos,length;
            for(i=0;i<10;i++) cout<<c.pop()<<' ';
    }       cout<<endl;}
                  T *stck;};
4.类模板的继承与派生
   模板类的派生与普通类一样,也分为公有
    派生类、保护派生类和私有派生类三种。
   模板派生类中成员的访问控制规则与普通
    类也是一样的。
   下面给出常见的几种情况:
       普通类继承类模板
       模板类继承普通类
       模板类继承模板类
       模板类继承模板参数给出的基类
普通类继承类模板
   可以通过继承类模板的一个实例来声明一
    个类 ,例如:
template<class T>
class TBase{
      T data;
……
};
class Derived:public TBase<int>{
……
};
模板类继承普通类

   模板类TDerived继承了普通类TBase,
    这种情况十分常见。 例如:
class TBase{
……
};
template<class T>
class TDerived:public TBase{
T data;
……
};
模板类继承模板类

   例如:
template<class T>
class TBase{
T data1;
……
};
template<class T1,class T2>
class TDerived:public TBase<T1>{
T2 data2;
……
};
      模板类继承模板参数给出的基类

        继承哪个基类由模板参数决定。
      #include<iostream>
        例12.5 分析程序输出结果。
   template<typename T,int value>
      using namespace std;
   class BaseC{
      class
void main() BaseA{
{ private:
      public:
          T data;
             BaseA(){cout<<"BaseA founed"<<endl;}
       Derived<BaseA> x;// BaseA作为基类
   public:
      };
       Derived<BaseB> y;// BaseB作为基类
          BaseC(T n=value):data(n){
      class 程序运行结果为:
             BaseB{
       Derived<BaseC<int,3> > z;
      public: cout<<"BaseC founed "<<data<<endl;}
            BaseA founed
      // BaseC<int,3>作为基类
} };        Derived founed
             BaseB(){cout<<"BaseB founed"<<endl;}
            BaseB T>
   template<class founed
      };
   class Derived:public T{
            Derived founed
   public: BaseC founed 3
          Derived():T(){cout<<"Derived
            Derived founed
   founed"<<endl;}};
类模板和模板类小结

   类模板是一个类型参数化的样板,它是一
    组模板类的集合。
   模板类是某个类模板的实例。
   使用某个具体的类型来替换某个类模板的
    模板参数可以生产该类模板的一个模板类。
   可以通过模板类再创建具体的对象。
   类模板的作用:让类参数化,以加强其通
    用性,提供代码的重用率。
练习与作业

						
Related docs
Other docs by xhch