C++模板

原创 2005年05月22日 18:05:00

C++模板

模板首先是一种设计理念,其次才是一种C++语法。只有先理解了模板,才能更好的使用C++中的模板特性。

模板的概念

为了能理解模板,可以先了解一下模具:为了生产一种产品,例如茶具,需要先设计其模具,有了模具后,能够轻易地成批量的生产出成千上万的产品。模具的特点是一次设计,反复使用。模具具有了模板的重用性特点;但却少了可扩展的特点:其产品是一成不变的,如果某人想把茶具的外形少作改动,则此模具就作废了。

为了兼有重用性和可扩展的优点,需要将不变的部分和变化的部分分开,把不变的部分做成模具骨架,把变化的部分作为模具的子部分存在。例如对汽车,可以认为车架、油路系统、电路系统,轮胎构成了一辆汽车的骨架,至于是什么样的车架、油路系统、电路系统在骨架中不体现出来,只是把这些部分的接口数据全定义出来了,只要满足这些定义的子部分部件,都能往骨架中放。可以这么简单的理解:骨架都有一些占位符组成,占位符组成有其定义,符合这些占位符定义的符号都能放入骨架中,以实现不同的功能。

现在把模板的定义上升到理论高度:“定义一个操作中算法的骨架,而将一些步骤延迟到子类中”[1];“各子类的公共行为被提前提取出并集中到一个公共父类中避免代码重复”[1]

需要说明的是,这里所说的子类不是只对模板类的派生,而是指模板类的参数化类别。模板已是设计模式[1]之一;模板通常有两个角色:

抽象类:定义抽象的原语操作(可以简单的定义了一些接口),其具体实现放到子类中;

具体类:实现原语操作以完成算法中与特定子类相关的步骤,即实现抽象类定义的接口。

模板的语法

C++中,分两个层次使用模板:模板函数,模板类。

模板函数

一般在头文件中定义模板函数,如

#ifndef _POS_H_

#define _POS_H_

template<class T>

T* pos(cosnt T& value, T* beginT* end)

{

for(; begin < end; begin ++)

{

    if(*begin == value)

{

    return begin;

}

 

}

}

#endif

要使用模板函数,需要对模板函数进行实例化,如下的例子使模板被实例化两次:

#include “pos.h”

#include <string>

using namespace std;

int main(int argc, char ** argv)

{

int int_array[30];

string string_array[30];

int iptr = pos(-1, &int_array[0], &int_array[30]);

string* sptr = pos(string(“sam”, &string_array[0], &string_array[30]);

    return 0;

}

模板类

模板类的定义与模板函数类似,可以把模板类的成员函数与类定义一起放到头文件中,如:

#ifndef _VECTOR_H_

#define _VECTOR_H_

template <class T>

class Vector

{

};

 

template <class T>

vector<T>::vector():tptf(new T[10], length(10){}

//对于在cpp文件中的实现方式同样需要如此定义

#endif

模板类的使用也类似,如:

#include <Vector.h>

int main(int argc, char** argv)

{

Vector<int> int_vec;

Vector<string> str_vec;

return 0;

}

模板特化

模板特化分两种:完全特化和偏特化;完全特化是模板的一种穷举方式,是指参数的完全固定化,即所以参数都有一个具体的类型,如:

template<bool> struct CompileTimeChecker{};

template<> struct CompileTimeChecker<true>

{

CompileTimeChecker(…){};

};

后者即是模板类CompileTimeChecker类的特化版本,因为它把bool类型的参数固定为true

而偏特化与完全特化是想对的,只有一个参数的模板类,无法偏特化;这是因为偏特化只能固定模板类的部分参数,而非全部(如果是全部,就变成了完全特化了)。如:

template<class T, class U>

class Conversion

{

};

template <class T>

class Conversion<T, T>

{

public:

    enum{exists = 1, sameType = 1};

}

后者实现了对模板类Conversion的偏特化版本,即两个参数TU类型相同的情况。Visual C++ 6不支持对模板类的偏特化。

type traits

Type Traits是范型编程中用于编译是类型判断的一项技术,其主要思想是利用函数特化(特别是完全特化),来为模板类定义一些辅助常量和函数,以便于在编译时进行类型判断。例如,想对指针和非指针类型做区分,以编译进行不同的处理,就可以使用Type Traits技术。

Template <typename T>

Class TypeTraits

{

private:

   template<class U>struct PointerTraits

   {

enum{result = false;};

typedef NullType PointeeType;

   };

   template<class U> struct PointerTraits<U*>

{

   enum{result = true ;};

  typedef U PointeeType;

;

public:

enum{isPointer = PointerTraits::result};

typedef PointerTraits<T>::PointeeType PointeeType;

};

上面的例子,把非指针类型定义其枚举变量resultfalse,这是一种范型结果;而对指针类型,利用特化版本,另外定义其结果为true;为了对外有一致的接口,对非指针类型用了一个空指针占位NullType,并都定义了类型PointeeType。在模板实例化时,会根据不同的参数类型调用不同的版本。

TypeTraits的主要用途主要是用于代码优化,因为如果知道类型后,就能利用特殊方法进行处理。如对char的复制,可以直接使用memcpy,这是C++中最快的复制方式;对有双CPU的机器,可以使用直接比特流复制等。

模板与编译器

编译器怎么样实现模板的呢?

²        编译:在编译如上的例子程序时,编译器从pos.h中读到了模板定义,并根据在main中实例化的情况,编译器会自动生成两个版本的pos函数:pos(const int&, int*, int*)pos(string&, string*, string*)

²        Borland C++VC Sun Workshop HP aCCG++:编译器在main.o或者main.obj中扩展pos函数两次。

²        EDG-based C++或者G++-frepo参数:编译器直到链接时才展开pos函数,但编译时会在本地数据库(EDGmain.ii-实例化信息文件,G++main.pro-仓库文件)中生产记录参数化信息。

模板的副作用

模板是好东西,但也有其副作用,世界就是这么公平:

对于链接时实例化:链接更加耗时;在实例化时会递归很多此来得到所以成员函数的全部版本。

对眼编译时实例化:目标代码变大;很难有选择地实例化模板类成员函数地几个版本,即实现全部版本。

会带来不必要的代码编写,如模板类中实现了操作符<<,并在其中引用此操作符,在实例化模板类时,编译器会要求你的类实现此操作符,即是你的应用程序根本不会使用此操作符,否则编译失败。

结束语

模板技术常用于类库编程和范型编程,因为其主要思想是提炼算法骨干,延迟细节处理;使用好了模板将使类库代码短小精悍;模板读设计思路是一种抽象和复用,能够提高设计的效率。

参考书目

²        [1] STL源码剖析,侯捷。

²        [2] C++ 设计新思维,Andrei Alexandrescu.

C++ 模板的显示具体化

C++ 没有办法限制类型参数的范围,我们可以使用任意一种类型来实例化模板。但是模板中的语句(函数体或者类体)不一定就能适应所有的类型,可能会有个别的类型没有意义,或者会导致语法错误。 ...

使用C++实现AVL树模板

今天练习编写了一下AVL树。参考了Weiss的数据结构与算法C++描述版。上一个实现的一个一般的二叉搜索树,在使用的过程中可能会慢慢变得不平衡,这样很可能会降低查找、插入等等的效率,因此我们需要使用算...
  • cjbct
  • cjbct
  • 2016年12月13日 22:32
  • 1082

C++模板库 list 的使用方法总结

转载自: http://www.cnblogs.com/rushoooooo/archive/2011/09/03/2164623.html 本文主题        这几...

平衡二叉树的C++模板实现

本文内容为前天写的AVL树模板的C++代码实现。本想把

C++中的类模板详细讲述

C++中的类模板详细讲述   一、类模板定义及实例化 1. 定义一个类模板: View Code 1 templateclass 模板参数表>2 3 class 类名{4 5 // 类定...

C++标准库,标准程序库,标准模板库之间是什么关系(重要!!!)

C++强大的功能来源于其丰富的类库及库函数资源。C++标准库的内容总共在50个标准头文件中定义。在C++开发中,要尽可能地利用标准库完成。这样做的直接好处有:           (1)成本:已经作为...

c++ 大数类 大数模板

转自:http://blog.csdn.net/hackbuteer1/article/details/6595881 分别使用C++中的运算符重载的方法来实现大数之间的数学运算,包括加法、减法、乘...
  • vsooda
  • vsooda
  • 2013年01月25日 20:23
  • 15874

C++模板类编程的链接问题

问题引入前两天想写一个模板类,里面放一些编程的时候常用的函数,比如动态创建二维数组。下面是我一开始写的代码://templateLibrary.h #include template clas...

C++ STL标准模板库类String成员详细列表参考及示例代码

STL的代码从广义上讲分为三类:algorithm(算法)、container(容器)和iterator(迭代器),几乎所有的代码都采用了模板类和模板函数的方式,这相比于传统的由函数和类组成的库来说提...
  • yuzeze
  • yuzeze
  • 2016年06月13日 10:49
  • 1226

用 C++ 标准模板库(STL)的 vector 实现二叉搜索树(BST)

本文由 Justme0 翻译自 Code Project 转载请参见文章末尾处的要求。 介绍 众所周知,要建一棵树,我们需要关注它的内存分配与释放。为了避开这个问题,我打算用C++ STL(ve...
  • Justme0
  • Justme0
  • 2013年09月05日 17:31
  • 4183
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C++模板
举报原因:
原因补充:

(最多只允许输入30个字)