来源:http://c.chinaitlab.com/cc/ccjq/200806/752604_2.html

--  template 的用法
    在程序设计当中经常会出现使用同种数据结构的不同实例的情况。例如:在一个程序中
    可以使用多个队列、树、图等结构来组织数据。同种结构的不同实例,也许只在数据元素
    的类型或数量上略有差异,如果对每个实例都重新定义,则非常麻烦且容易出错。那么能
    否对同种类型数据结构仅定义一次呢?答案是肯定的,C++提供的类模板(Class Template
    )就可以实现该功能。
    一、类模板
    类模板是C++提供的一种特殊机制,通过它我们可以定义一种特殊的类(称为模板类),在类
    的定义中可以包含待定的类型参数,在声明类的实例时,系统会自动根据传递的类型生成
    用户想要生成的类实例。下面是用C++实现的一个简单的模板类Clist的定义。

  Template <class T, int I> class CList
{
public:
int SetItem(int Index, const T &Item);
int GetItem(int Index, T &Item);
private:
T Buffer;
}

在这里,T是类型参数,I是整型常量参数。T和I的实际值是在声明具体类实例时指定的。
    模板类的<>号内可以包括任意个类型参数和常量参数(至少要有一个参数)。类型参数和
    常量参数可以是任何合法的标准类型和用户自定义类型,包括简单类型及各种结构体。同
    其他类一样,类成员函数SetItem的实现可以在类定义内完成,也可以在类CList定义处实
    现:

 template<class T, int I> int CList<T, I>::SetItem(int Index, const T &Item)
{
if ( (Index<)||(Index>I-) )
 return ; // 出错
Buffer[Index]= Item ;
 return ; // 成功
}

值得注意的是,在类定义外完成函数实现时,必须以关键字template和类模板定义中相同
    的参数表(<>号内的)开头(上例为template<class T, int I>),并且范围分解操作符前的
    类名后应跟上模板参数名清单(上例为CList<T, I>)。另外,与非模板类不同的是,必须将
    函数实现包括在调用它的每个源文件中,使编译器能从函数实现产生代码。通常的做法是
    将模板类的函数实现也放在定义该类的头文件中,这样只需在调用的源文件中包含该头文
    件即可。
    那么,如何使用生成特定的类实例呢?我们可以像使用其他类一样来使用模板类,不过必须
    指定模板参数的值。例如采用如下声明:
    CList <int, 100> IntList;
    则使IntList成为CList类的实例,每次出现的T参数都换成int, 每次出现的I参数都换成
    100。这样,IntList类中的Buffer就是一个长度为100的整型数组,SetItem和GetItem函数
    参数是int值的引用。例:
    IntList.SetItem(0, 5); //给数组第一个元素赋为整数5
    模板类还可以像其他类一样可以定义构造函数和析构函数。下面我们以一种简单的数据
    结构——堆栈为例,来说明如何用类模板来构造通用数据结构。
    二、 利用类模板实现通用堆栈结构
    任何抽象数据结构在计算机中的实现,归根结底都只有两种方式:顺序存储(用数组实现)
    ,链式存储(用指针实现)。堆栈也不例外,按其实现方式可分为顺序栈(用数组实现)和链
    栈(用指针实现)。
    1. 通用顺序栈的实现
    因为顺序栈中的元素在空间上连续存储,栈顶的元素位置需要注明,所以构造顺序栈的模
    板类应该有这样的一些成员变量:一个待定类型和长度的数组Buffer,一个记录栈顶元素
    的数组下标的整型变量top。堆栈的基本操作主要有:入栈(Push)、出栈(Pop)、置空(Se
    tEmpty)、判断当前状态(IsEmpty)等,它们应用模板类的成员函数来实现。作为一个标准
    的类,它还应该有自己的构造函数和析构函数。具有这些功能的模板类,就可以作为一个
    通用的顺序栈来使用了。该类的定义如下:

 template <class T,int SIZE> class CArrayStackTemp
{
public:
CArrayStackTemp () //缺省构造函数,构造一个空堆栈
{
top= -;
};
~ CArrayStackTemp (){};//析构函数
 void SetEmpty (); //置空堆栈
 bool IsEmpty(); //判断堆栈是否为空
 bool Push(T element); //入栈
 bool Pop(T& element);//出栈
private:
T Buffer[SIZE];
 int top;
};

与堆栈的基本操作相对应的成员函数的实现如下:

 template <class T, int SIZE> void CArrayStackTemp<T, SIZE>:: SetEmpty ()
{
top= -; //将栈顶指针赋 -1,并不实际清除数组元素
}
template <class T, int SIZE> bool CArrayStackTemp<T, SIZE>:: IsEmpty ()
{
return(top == -);
}
template <class T, int SIZE> bool CArrayStackTemp<T, SIZE>:: Push (T element
)
{
top++;
if (top>SIZE-)
{
top--;
return false; //堆栈已满,不能执行入栈操作
}
Buffer[top]=element;
return true;
}
template <class T, int SIZE> void CArrayStackTemp<T, SIZE>:: Pop (T& element
)
{
if (IsEmpty())
 return false;
element =Buffer[top];
top--;
return true;
}

根据实际需要,还可以扩充堆栈功能。例如:加入取栈顶元素、求堆栈长度等操作,其方法
    如上。
    2. 通用链栈的实现
    模板类中允许使用指针和定义自己的结构,这就为实现链式结构提供了保证。这里采用一
    个单链表来实现堆栈,栈顶指针指向链表的第一个结点,入栈和出栈均在链表的头进行。
    该模板类的定义如下:

 template <class T> class CLinkStackTemp
{ public:
 //类的缺省构造函数,生成一个空堆栈
CLinkStackTemp ()
{
top=NULL;
};
~ClinkStackTemp(){}; //析构函数
 //定义结点结构
 struct node
{
T
  data; //入栈元素
 node* next; //指向下一结点的指针
};
 void SetEmpty(); //置空堆栈
 bool IsEmpty(); //判断堆栈是否为空
 bool Push(T element); //压入堆栈
 bool Pop(T& element);//弹出堆栈
private:
 node* top;
};

该类的成员函数实现如下:

 template <class T> void CLinkStackTemp <T>::SetEmpty()
{
//释放堆栈占用的内存
node* temp;
while (top!=NULL)
{
 temp=top;
 top=top->next;
 delete temp;
}
}
template <class T> bool CLinkStackTemp <T>::IsEmpty()
{
return (top==NULL);
}
template <class T> bool CLinkStackTemp <T>::Push(T element)
{
node* temp=new node();
if (temp ==NULL)
 return false ;
temp->data=element;
temp->next=top;
top=temp;
return true;
}
template <class T> bool CLinkStackTemp <T>::Pop(T& element)
{
if ( IsEmpty())
 return false;
node* q = top;
element = top->data;
top=top->next;
delete q;
return true;
}

与顺序栈的实现略有不同,链栈不必指定栈的容量,其大小可以是近似"无限"的。为了程
    序的使用方便,我们同样可以加入一些增强的功能。
    三、 通用堆栈类的使用
    通用堆栈类的使用较为简单,堆栈类的实例就是一个可以方便使用的堆栈。对堆栈的操作
    都是通过类的成员函数来实现的。使用的具体步骤如下:
    1. 在要使用堆栈类的程序代码的文件开头包括模板类及其成员函数的定义。
    2. 类的实例化,可声明成变量,也可以声明它的指针,如:
    CArrayStackTemp <int, 100> intStack; //生成一个长度为100的int型堆栈
    //生成一个元素为Record型的堆栈,Record为自定义结构
    CLinkStackTemp <Record>* RecordStack;
    RecordStack=new CLinkStackTemp<Record>;
    应注意在定义顺序栈时,必须指定栈的大小,而链栈则不必。另外在指定指针类型和执行
    new操作时,必须对模板参数赋值,并且前后要一致。
    3. 对堆栈进行操作,如:
    intStack.Push(3); //将整数3入栈
    RecordStack.SetEmpty(); //将堆栈置空
    无论我们使用哪种堆栈类,对用户来讲都是透明的,操作起来并无差别。

C++ primer里的template用法的更多相关文章

  1. Hibernate(或其它ORM)里的inverse用法详解,内容摘自Java web轻量级开发面试教程

    本文来是从 java web轻量级开发面试教程从摘录的. Inverse的英文含义是反转,在Hibernate中用来决定是由哪方来维护两个业务实体类之间的关联关系,具体而言,就是由哪方去设置这个被外键 ...

  2. Go标准库:Go template用法详解

    本文只介绍template的语法和用法,关于template包的函数.方法.template的结构和原理,见:深入剖析Go template. 入门示例 以下为test.html文件的内容,里面使用了 ...

  3. vue里ref ($refs)用法

    ref 有三种用法: 1.ref 加在普通的元素上,用this.ref.name 获取到的是dom元素 2.ref 加在子组件上,用this.ref.name 获取到的是组件实例,可以使用组件的所有方 ...

  4. Linux编程里getopt_long_only函数用法详解

    在程序中难免需要使用命令行选项,可以选择自己解析命令行选项,但是有现成的,何必再造轮子.下面介绍使用getopt_long_only和getopt_long(两者用法差不多)解析命令行选项. 程序中主 ...

  5. ABAP里SELECT的用法汇总(转)

    通常使用Open SQL的数据查询语句SELECT将数据库条目选择到内存.一.SELECT语句:1)SELECT用于确定读取数据表中的哪些字段:2)FROM子句用于确定从哪些内表或者视图中读取数据:3 ...

  6. 【译】css动画里的steps()用法详解

    原文地址:http://designmodo.com/steps-c... 原文作者:Joni Trythall 我想你在css 动画里使用steps()会和我一样有很多困惑.一开始我不清楚怎样使用它 ...

  7. SQL里IN的用法以及优化

    1.in后条件不多,可以考虑主表建索引,或用union all 代替 2. in 和 exists的区别: 如果子查询得出的结果集记录较少,主查询中的表较大且又有索引时应该用in, 反之如果外层的主查 ...

  8. android里Toast的用法

    在活动中,可以通过findViewById()方法获取到在布局文件中定义的元素,这里我们传入R.id.button_1,来得到按钮的实例,这个值是刚才在first_layout.xml中通过andro ...

  9. KEIL里 Volatile的用法

    volatile用于防止相关变量被优化. 例如对外部寄存器的读写.对有些外部设备的寄存器来说,读写操作可能都会引发一定硬件操作,但是如果不加volatile,编译器会把这些寄存器作为普通变量处理,例如 ...

随机推荐

  1. POJ1004Financial Management

    这个题犯了一个小小的错误,double输出的时候用f才对,输入用lf即可.... http://poj.org/problem?id=1004 #include<stdio.h> int ...

  2. lintcode 中等题:搜索旋转排序数组II

    题目 搜索旋转排序数组 II 跟进“搜索旋转排序数组”,假如有重复元素又将如何? 是否会影响运行时间复杂度? 如何影响? 为何会影响? 写出一个函数判断给定的目标值是否出现在数组中. 样例 给出[3, ...

  3. lintcode 中等题: reverse linked list II 翻转链表II

    题目 翻转链表 II 翻转链表中第m个节点到第n个节点的部分 样例 给出链表1->2->3->4->5->null, m = 2 和n = 4,返回1->4-> ...

  4. Linux进程管理知识整理

    Linux进程管理知识整理 1.进程有哪些状态?什么是进程的可中断等待状态?进程退出后为什么要等待调度器删除其task_struct结构?进程的退出状态有哪些? TASK_RUNNING(可运行状态) ...

  5. Java开发--操作MongoDB

    http://www.cnblogs.com/hoojo/archive/2011/06/01/2066426.html介绍到了在MongoDB的控制台完成MongoDB的数据操作,通过前一篇文章我们 ...

  6. ARM(ARM处理器)

    ARM是微处理器行业的一家英国公司,其设计了大量高性能.廉价.耗能低的RISC处理器.相关技术及软件,公司并不直接生产产品,而是采用出售芯片技术授权的商业模式盈利.技术具有性能高.成本低和能耗省特点. ...

  7. 修改Eclipse字体

    选择菜单:Windows->Preferences->Genneral->Appearance->Colors and Font

  8. 利用PC创建一个无线接入点

    win7 创建虚拟接入点,修改接入点名称和密码,然后存为bat文件,以管理员模式运行 netsh wlan set hostednetwork mode=allow ssid=APName key=p ...

  9. 从输入 URL 到页面加载完的过程中都发生了什么---优化

    这篇文章是转载自:安度博客,http://www.itbbu.com/1490.html 在很多地方看到,感觉不错,理清了自己之前的一些思路,特转过来留作记录. 一个HTTP请求的过程 为了简化我们先 ...

  10. MariaDB10.2.X-新特性2-支持check约束and with as

    前几天写了一篇MariaDB10.2支持分析函数,大家印象中MySQL不支持with as ,check约束,那么MariaDB10.2也同样给你惊喜 1.with as MariaDB [test1 ...