如果两种类只是数据类型不同,而其他代码是相同的,与其编写新的类声明,不如编写一种泛型(独立于类型的)栈。然后将具体的类型作为参数传递给这个类。这样就可以使用通用的代码生成存储不同类型值的栈。

可以使用typedef处理这样的需求,但是有两个问题,一、每次修改类型都必须重新编辑头文件;二、在每个程序中都只能使用这种技术生成一种栈。

C++的类模板为生成通用的类声明提供了一种更好的方法;模板提供参数化类型,能够将类型名作为参数传递给接收方来建立类或函数。

C++标准模板库(STL)提供了几种功能强大而灵活的容器类模板。

定义模板类

template <class Type>,template告诉编译器,将要定义一个模板。尖括号内容相当于函数的参数列表。

也可以这么写:

template <typename Type>

或是:

template <class T>

template <typename T>

当模板被调用时,Type将被具体的类型值(int或string)取代。

原来类的声明:

typedef unsigned long Item;

class Stack

{

private:

enum {MAX = 10};

Item items[MAX];

int top;

public:

Stack( );

bool isempty( ) const;

bool isfull( ) const;

bool push (const Item & item);

bool pop(Item & item);

}

类模板信息必须都放在头文件中,不能把模板成员函数放到独立的实现文件中。因为模板不是函数,不能单独编译。在要使用这些模板的文件中包含该头文件

类模板:

template<class Type>

Stack<Type>::Stack()

{

}

template <class Type>

bool Stack<Type>::isempty()

{

}

template <class Type>

bool Stack<Type>::isfull()

{

}

template <class Type>

bool Stack<Type>::push(const Type & item)

{

}

template <class Type>

bool Stack<Type>::pop(Type & item)

{

}

使用类模板

仅在程序包含模板并不能生成模板类,而必须请求实例化。需要声明一个类型为模板类的对象,并且使用所需的具体类型替换泛型名。

Stack<int> kernels;

Stack<string>colonels;

看到上述两个声明后,编译器将按Stack<Type>模板来生成两个独立的类声明和两组独立的类方法。

泛型标识符——Type——被称为类型参数,这意味着它类似于变量,但是赋给它们的不能是数字,而只能是类型。

必须,显式地提供所需的类型,这与常规的函数模板是不同的。

深入探讨模板类

可以将内置类型或对象作为类模板Stack<Type>的类型。指针也是可以的。但是如果不对程序做重大修改,将无法很好地工作。

创建不同的指针是调用程序的职责,而不是栈的职责。栈的任务是管理指针,而不是创建指针。

字符串本身永远不会移动,把字符串压入栈实际上是新建一个指向该字符串的指针,即创建一个指针,该指针的值是现有字符串的地址。

构造函数使用new创建一个用于保存指针的数组,析构函数删除该数组,而不是数组元素指向的字符串。

数组模板示例和非类型模板

常用作容器类,这是因为类型参数的概念非常适合于将相同的存储方案用于不同的类型。引入模板的主要动机是:容器类可提供重用的代码。

深入探讨模板设计和使用的其他几个方面。

具体来说,探讨一些非类型(或表达式)参数以及如何使用数组。

实现一种允许指定数组大小的简单数组模板:

方法一:在类中使用动态数组和构造函数参数来提供元素数目;->旧方法

方法二:使用模板参数来提供数组的大小;

模板头:template<class T, int n>

class 关键字标识这是类型参数,int指出n的类型为int,这是非类型参数,或表达式参数

表达式参数有一些限制:可以是整型,枚举,引用或指针。

表达式参数的优点:使用自动变量维护内存栈,而不是用构造函数方法使用的new,delete来管理内存。

表达式参数的缺点:下面的声明将生成两个独立的类声明;

ArrayTP<double, 12> eggweights;

ArrayTP< double, 13> eggweights;

而构造函数的方法,就只要一份类声明。

另一个区别是:构造函数的方法更通用。数组大小是作为类数据成员存储在定义中。

模板多功能性

模板的作用

用作基类

用作组件类

用作其他模板的类型参数

数组模板实现栈模板

数组模板来构造数组

递归使用模板

使用多个类型参数

template<class T1, class T2>

默认类型模板参数

可以为类型参数提供默认值;

template<class T1, class T2=int>

类模板:类型参数可提供默认值;

函数模板的类型参数不可听默认值;

非类型参数:类模板,函数模板都可以提供默认值;

模板的具体化

模板以泛型的方式描述类;

具体化是使用具体的类型生成类声明;

1、 隐式实例化

是指在需要对象之前,不会生成类;

ArrayTP<double,30> * pt;  //一个指针,还没有对象被创建

pt = new ArrayTP<double,30>;  //创建一个对象

2、 显式实例化

template class ArrayTP<string,100>; //会产生一个类的实例,声明一个类;

虽然没有创建或提及类对象,编译器也将生成类声明。

3、 显式具体化

指的是特定类型的定义。

4、部分具体化

成员模板

模板可用作结构、类或模板类的成员。

类的成员(数据,方法)->都可以用模板表示;

而不仅仅是类用模板表示;

模板之中有模板,嵌套的;还可以在模板之外定义方法模板,成员模板;

将模板用作参数

将模板用作模板的参数;

模板包含类型参数和非类型参数:

template <template <typename T> class Thing>

template <typename T> class Thing  是模板的参数;

其中template <typename T> class  是参数模板(把模板作为参数用);是类型;

假设有以下声明:

Crab<King> legs;

Crab<King>是模板Crab具体的类型;模板参数是King,King也必须是一个模板类。

template <typename T>

class King {…};

模板类和友元

模板类声明也可以有友元。(友元:模板or非模板, 约束or非约束)

l  非模板友元;

l  约束模板友元,即友元的类型取决于类被实例化时的类型;

l  非约束模板友元,即友元的所有具体化都是类的每一个具体化的友元;

1、 模板类的非模板友元函数

在模板类中将一个常规函数声明为友元:

template <class T>

class HasFriend

{

public:

friend void counts();

};

counts()函数成为模板所有实例化的友元。例如,它将是类hasFriend<int>和HasFriend<string>的友元。该友元与所有模板实例化的对象都具有友元关系(一对多)。该函数不是通过对象调用,没有对象参数。

template <class T>

class HasFriend

{

public:

friend void report(HasFriend<T> &);

};

这一种带模板类参数的友元。这是一种一对一的友元关系,即该友元只是某个具体类型的模板的友元函数。

2、 模板类的约束模板友元函数

3、 模板类的非约束模板友元函数

普通类+普通友元 (一对一)友元-类而言

普通类+模板友元 (多对一)友元-类而言

模板类+普通友元 (一对多)友元-类而言

模板类+模板友元 (多对多)友元-类而言

模板别名(C++)

 

C++_代码重用5-类模板的更多相关文章

  1. C++_代码重用1-总览

    C++的主要目的是促进代码重用. 公有继承是实现这一目标的机制之一: 本身是另一个类的成员,这种方法称为包含.组合.层次化. 另一种方法是使用私有.保护继承. 通常包含.私有继承和保护继承用于实现ha ...

  2. C++_代码重用2-包含对象成员的类

    对于姓名可以使用字符数组来表示,但这将限制姓名的长度.当然,还可以使用char指针和动态内存分配,但这要求提供大量的支持代码.有一个好的方法就是使用一个他人开发好的类的对象来表示.如果C++库提供了合 ...

  3. C++_代码重用3-私有继承

    使用包含:易于理解,类声明中包含表示被包含类的显式命名对象,代码可以通过名称引用这些对象: 使用继承:将使关系更抽象,且继承会引起很多问题,尤其是从多个基类继承时. 私有继承所提供的特性确实比包含多. ...

  4. C++_代码重用4-多重继承

    继承使用时要注意,默认是私有派生.所以要公有派生时必须记得加关键字Public. MI(Multi Inheritance)会带来哪些问题?以及如何解决它们? 两个主要问题: 从两个不同的基类继承同名 ...

  5. C/C++:类模板

    类模板就是为类声明一种模板,使得类中的某些数据成员,或某些成员函数的参数,又或者是某些成员函数的返回值可以取任意的数据类型,包括基本数据类型和自定义数据类型. 类模板的声明形式如下: template ...

  6. C++解析(27):数组、智能指针与单例类模板

    0.目录 1.数组类模板 1.1 类模板高效率求和 1.2 数组类模板 1.3 堆数组类模板 2.智能指针类模板 2.1 使用智能指针 2.2 智能指针类模板 3.单例类模板 3.1 实现单例模式 3 ...

  7. C++中的单例类模板

    1,本节课讲述单例类模式,实现并抽取相关代码实现单例类模板,在以后开发工作 中,如果想要使用单例模式,那么直接使用今天开发的单例类模板就可以: 2,需求的提出: 1,在架构设计时,某些类在整个系统生命 ...

  8. C++_进阶之函数模板_类模板

     C++_进阶之函数模板_类模板 第一部分 前言 c++提供了函数模板(function template.)所谓函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体制定,用一个虚拟的类型来 ...

  9. 谈谈Delphi中的类和对象4---类是一种对数据和操作高度的封装机制 && 类是一种代码重用机制

    五.类是一种对数据和操作高度的封装机制 1)数据封装 unit Unit2; interface type TEmployee = class; private FName: String; publ ...

随机推荐

  1. 分布式缓存产品Redis和memcached比较区别(图)

  2. 场景中,并没有灯源的存在,但是cube却会有灯光照射的反应,这就是Light Probe Group的作用。

    http://blog.csdn.net/qq617119142/article/details/41674755

  3. c++原型模式(Prototype)

    原型模式是通过已经存在的对象的接口快速方便的创建新的对象. #include <iostream> #include <string> using namespace std; ...

  4. 507. Perfect Number 因数求和

    [抄题]: We define the Perfect Number is a positive integer that is equal to the sum of all its positiv ...

  5. 单机配置tomcat 8 集群

    如何能在集群中的多个节点之间保持数据的一致性,会话(Session)信息是这些数据中最重要的一块. 本文当采用tomcat默认集群配置(<Cluster className="org. ...

  6. hrabs的数据库session的修改

    using System;using System.Data;using System.Collections;using System.Collections.Generic;using Syste ...

  7. nodelet的应用

    1.创建一个包,如example_pkg catkin_create_pkg example_pkg 2.创建MyNodeletClass.h文件 cd ~/catkin_ws/src/example ...

  8. Oracle——单行函数

    两种 SQL 函数 单行函数 字符函数 大小写控制函数 SELECT employee_id, last_name, department_id FROM employees WHERE last_n ...

  9. MSGPACK和PROTOBUF的故事(MSGPACK明显生产力不足)

    作者曾经在2014年测试出MSGPACK的关键字和中文字符有很大的冲突,所以后来放弃了,本文为很多年前写的一个对比,后来我们一直在使用HTTP协议和PROTOBUF. 看看MSGPACK的文档,自称效 ...

  10. _AppStart.cshtml 和 _PageStart.cshtml的妙用

    Customizing Site-Wide Behavior for ASP.NET Web Pages (Razor) Sites By Tom FitzMacken|February 17, 20 ...