模板类

根据参数类型生成函数和类的机制

模板类是根据参数类型生成函数和类的机制(有时称为“参数决定类型”)。

简介
通过使用模板,可以只设计一个类来处理多种类型的数据,而不必为每一种类型分别创建类。
优势
创建一个类型安全函数来返回两个参数中较小的一个,如果不使用Templates,必须要编写一系列如下的函数:
// min for ints
int min( int a, int b )
return ( a < b ) ? a : b;
// min for longs
long min( long a, long b )
return ( a < b ) ? a : b;
// min for chars
char min( char a, char b )
return ( a < b ) ? a : b;
//etc...
使用templates,可以减少重复部分,形成一个函数:
template
type min( type a, type b )
return ( a < b ) ? a : b;
模板能够减少源代码量并提高代码的机动性而不会降低类型安全
何时使用模板
模板经常被用来实现如下功能:
>> 创建一个类型安全的集合类(例如,堆栈)用来处理各种类型的数据
>> 为函数添加额外的类型检查以避免获得空指针
>> 合并操作符重载组来修改类型行为(例如智能指针smart pointer)
大多数以上应用可以不用模板实现;但是,模板具有以下几个优势:
>> 开发容易。你可以只为你的类或函数创建一个普通的版本代替手工创建特殊情况处理。
>> 理解容易。模板为抽象类型信息提供了一个直截了当的方法。
>> 类型安全。模板使用的类型在编译时是明确的,编译器可以在发生错误之前进行类型检查。
函数模板
函数模板(function templates)
使用函数模板,你可以指定一组基于相同代码但是处理不同类型或类的函数,例如:
template void MySwap( type& a, type& b )
{
type c( a );
a = b; b = c;
}
这段代码定义了一个函数家族来交换函数的参数值。从这个template你可以产生一系列函数,不仅可以交换整型、长整型,而且可以交换用户定义类型,如果类的构造函数和赋值操作符被适当地定义,MySwap函数甚至可以交换类。
另外,函数模板可以阻止你交换不同类型的对象,因为编译器在编译时知道参数a和b的类型。
你可以像调用一个普通函数一样调用一个函数模板函数;不需要特殊的语法。例如:
int i, j;
char k;
MySwap( i, j ); //OK
MySwap( i, k ); //Error, different types.
可以对函数模板的template参数作外部说明,例如:
template void f(T) {...}
void g(char j)
{ f(j);
//generate the specialization f(int)
}
template参数在外部说明时,普通固定的类型转换转换函数的参数为相应的函数模板参数。在上面的的例子中,编译器会将(char j)转换成整型
类模板
类模板(class templates)可以使用类模板创建对一个类型进行操作的类家族。
template // template<模板参数表>
class TempClass //class 类名TempClass
{public:
TempClass(void);
~TempClass( void );
int MemberSet( T a, int b );
private:
T Tarray;
int arraysize;
};
在这个例子中,模板类使用了两个参数,一个数据类型参数T和一个整型i,T参数可以传递一个类型,包括结构和类,i参数必须传递一个整数,因为I在编译时是一个常数,你可以使用一个标准数组声明来定义一个长度为i的成员数组模板与宏的比较(Templates vs. Macros)在很多方面,模板类似预处理宏,用给定的类型代替模板的变量。然而,模板和宏有很大的区别:
宏:
#define min(i, j) (((i) < (j)) ? (i) : (j))
模板:
template
T min (T i, T j)
{ return ((i < j) ? i : j) }
使用宏会带来如下问题:
>> 编译器没有办法检查宏的参数的类型是否一致。宏的定义中缺少特定类型的检查。
>> 参数i和j被被调用了2次。例如,如果任一个参数有增量,增量会被加两次。
>> 因为宏被预处理程序编译编译器错误信息会指向编译处的宏,而不是宏定义本身。而且,在编译阶段宏会在编译表中显露出来。
模板和空指针的比较(Templates VS. Void Pointers)
现在很多用空指针实现的函数可以用模板来实现。空指针经常被用来允许函数处理未知类型的数据。当使用空指针时,编译器不能区分类型,所以不能处理类型检查或类型行为如使用该类型的操作符、操作符重载或构造和析构。
使用模板,你可以创建处理特定类型的数据的函数和类。类型在模板定义里看起来是抽象的。但是,在编译时间编译器为每一个指定的类型创建了这个函数的一个单独版本。这使得编译器可以使用类和函数如同他们使用的是指定的类型。模板也可以使代码更简洁,因为你不必为符合类型如结构类型创建特殊的程序。
模板和集合类(Templates and Collection Classes)
模板是实现集合类的一个好方法。第四版及更高版本的Microsoft Foundation Class Library使用模板实现了六个集合类:CArray, CMap, CList, CTypedPtrArray, CtypedPtrList和 CtypedPtrMap。
MyStack集合类是一个简单的堆栈的实现。这里有两个模板参数,T和i,指定堆栈中的元素类型和堆栈中项数的最大值。push 和 pop成员函数添加和删除堆栈中的项,并在堆栈底部增加。
template class MyStack
{
T StackBuffer[i];
int cItems;
public:
void MyStack( void ) : cItems( i ) {};
void push( const T item ); T pop( void );
};
template void MyStack< T, i >::push( const T item )
{
if( cItems > 0 ) StackBuffer[--cItems] = item;
return;
}
template T MyStack< T, i >::pop( void )
{
if( cItems < i )
return StackBuffer[cItems++];
}
模板和智能指针(Templates and Smart Pointers)
C++允许你创建“智能指针”(“smart pointer”)类囊括指针和重载指针操作符来为指针操作增加新的功能。模板允许你创建普通包装来囊括几乎所有类型的指针。
如下的代码概括了一个简单的计数垃圾收集者参考。模板类Ptr为任何从RefCount继承的类实现了一个垃圾收集指针。
#include
#define TRACE printf
class RefCount
{
int crefs;
public:
RefCount(void) { crefs = 0; }
void upcount(void)
{
++crefs;
}
void downcount(void)
{
if (--crefs == 0) { delete this; }
}
};
class Sample : public RefCount
{
public:
void doSomething(void
};
template class Ptr
{
T* p;public: Ptr(T* p_) : p(p_) { p->upcount(); }
~Ptr(void) { p->downcount(); }
operator T*(void) { return p; }
T& operator*(void) { return *p; }
T* operator->(void) { return p; }
Ptr& operator=(Ptr &p_) {return operator=((T *) p_);}
Ptr& operator=(T* p_) { p->downcount(); p = p_; p->upcount(); return *this; }
};
int main()
{
Ptr p = new Sample;
// sample #1 Ptr p2 = new Sample;
// sample #2 p = p2;
// #1 will have 0 crefs, so it is destroyed;
// #2 will have 2 crefs. p->doSomething();
return 0;
// As p2 and p go out of scope, their destructors call
// downcount. The cref variable of #2 goes to 0, so #2 is
// destroyed
}
类RefCount 和 Ptr共同为任何一个从RefCount继承的能够提供整数的类的每一个实例提供了一个简单的垃圾收集解决方案。注意使用一个参数类如Ptr代替多个一般类如Ptr的主要好处在于这种形式是完全的类型安全的。前面的代码保证Ptr可以被用在几乎任何T* 使用的地方;相反,一个普通类Ptr只能提供到void*固有的转换。
例如,考虑一个用来创建和处理文件垃圾收集的类,符号、字符串等等。根据类模板Ptr,编译器可以创建模板类Ptr,Ptr, Ptr等等,和它们的成员函数:Ptr::~Ptr(), Ptr::operator File*(), Ptr::~Ptr(), Ptr::operator String*()等等。
相关介绍
大部分资料建议模板类的声明和实现都在.h文件中,这样能够保证正确链接。其实模板类也能够完成声明和实现分离,只是需要额外做一些处理。下面仍然以Stack为例:
//.h
template class MyStack
{
T StackBuffer;
int cItems;
public:
void MyStack( void ) : cItems( i ) {};
void push( const T item ); T pop( void );
};
//.cpp
template void MyStack< T, i >::push( const T item )
{...}
template T MyStack< T, i >::pop( void )
{...}
//在.cpp文件的最后,增加模板声明,把有可能用到的参数组合都进行声明即可
template class MyStack;
template class MyStack;
...
注意:这样做的缺点是,由于进行了声明,会把每一个参数组合都编译,生成的文件会非常大。
全国各地天气预报查询

上海市

  • 市辖区
  • 云南省

  • 临沧市
  • 云南省

  • 丽江市
  • 云南省

  • 保山市
  • 云南省

  • 大理白族自治州
  • 云南省

  • 德宏傣族景颇族自治州
  • 云南省

  • 怒江傈僳族自治州
  • 云南省

  • 文山壮族苗族自治州
  • 云南省

  • 昆明市
  • 云南省

  • 昭通市
  • 云南省

  • 普洱市
  • 云南省

  • 曲靖市
  • 云南省

  • 楚雄彝族自治州
  • 云南省

  • 玉溪市
  • 云南省

  • 红河哈尼族彝族自治州
  • 云南省

  • 西双版纳傣族自治州
  • 云南省

  • 迪庆藏族自治州
  • 内蒙古自治区

  • 乌兰察布市
  • 内蒙古自治区

  • 乌海市
  • 内蒙古自治区

  • 兴安盟
  • 内蒙古自治区

  • 包头市
  • 内蒙古自治区

  • 呼伦贝尔市
  • 内蒙古自治区

  • 呼和浩特市
  • 内蒙古自治区

  • 巴彦淖尔市
  • 内蒙古自治区

  • 赤峰市
  • 内蒙古自治区

  • 通辽市
  • 内蒙古自治区

  • 鄂尔多斯市
  • 内蒙古自治区

  • 锡林郭勒盟
  • 内蒙古自治区

  • 阿拉善盟
  • 北京市

  • 市辖区
  • 吉林省

  • 吉林市
  • 吉林省

  • 四平市
  • 吉林省

  • 延边朝鲜族自治州
  • 吉林省

  • 松原市
  • 吉林省

  • 白城市
  • 吉林省

  • 白山市
  • 吉林省

  • 辽源市
  • 吉林省

  • 通化市
  • 吉林省

  • 长春市
  • 四川省

  • 乐山市
  • 四川省

  • 内江市
  • 四川省

  • 凉山彝族自治州
  • 四川省

  • 南充市
  • 四川省

  • 宜宾市
  • 四川省

  • 巴中市
  • 四川省

  • 广元市
  • 四川省

  • 广安市
  • 四川省

  • 德阳市
  • 四川省

  • 成都市
  • 四川省

  • 攀枝花市
  • 四川省

  • 泸州市
  • 四川省

  • 甘孜藏族自治州
  • 四川省

  • 眉山市
  • 四川省

  • 绵阳市
  • 四川省

  • 自贡市
  • 四川省

  • 资阳市
  • 四川省

  • 达州市
  • 四川省

  • 遂宁市
  • 四川省

  • 阿坝藏族羌族自治州
  • 四川省

  • 雅安市
  • 天津市

  • 市辖区
  • 宁夏回族自治区

  • 中卫市
  • 宁夏回族自治区

  • 吴忠市
  • 宁夏回族自治区

  • 固原市
  • 宁夏回族自治区

  • 石嘴山市
  • 宁夏回族自治区

  • 银川市
  • 安徽省

  • 亳州市
  • 安徽省

  • 六安市
  • 安徽省

  • 合肥市
  • 安徽省

  • 安庆市
  • 安徽省

  • 宣城市
  • 安徽省

  • 宿州市
  • 安徽省

  • 池州市
  • 安徽省

  • 淮北市
  • 安徽省

  • 淮南市
  • 安徽省

  • 滁州市
  • 安徽省

  • 芜湖市
  • 安徽省

  • 蚌埠市
  • 安徽省

  • 铜陵市
  • 安徽省

  • 阜阳市
  • 安徽省

  • 马鞍山市
  • 安徽省

  • 黄山市
  • 山东省

  • 东营市
  • 山东省

  • 临沂市
  • 山东省

  • 威海市
  • 山东省

  • 德州市
  • 山东省

  • 日照市
  • 山东省

  • 枣庄市
  • 山东省

  • 泰安市
  • 山东省

  • 济南市
  • 山东省

  • 济宁市
  • 山东省

  • 淄博市
  • 山东省

  • 滨州市
  • 山东省

  • 潍坊市
  • 山东省

  • 烟台市
  • 山东省

  • 聊城市
  • 山东省

  • 菏泽市
  • 山东省

  • 青岛市
  • 山西省

  • 临汾市
  • 山西省

  • 吕梁市
  • 山西省

  • 大同市
  • 山西省

  • 太原市
  • 山西省

  • 忻州市
  • 山西省

  • 晋中市
  • 山西省

  • 晋城市
  • 山西省

  • 朔州市
  • 山西省

  • 运城市
  • 山西省

  • 长治市
  • 山西省

  • 阳泉市
  • 广东省

  • 东莞市
  • 广东省

  • 中山市
  • 广东省

  • 云浮市
  • 广东省

  • 佛山市
  • 广东省

  • 广州市
  • 广东省

  • 惠州市
  • 广东省

  • 揭阳市
  • 广东省

  • 梅州市
  • 广东省

  • 汕头市
  • 广东省

  • 汕尾市
  • 广东省

  • 江门市
  • 广东省

  • 河源市
  • 广东省

  • 深圳市
  • 广东省

  • 清远市
  • 广东省

  • 湛江市
  • 广东省

  • 潮州市
  • 广东省

  • 珠海市
  • 广东省

  • 肇庆市
  • 广东省

  • 茂名市
  • 广东省

  • 阳江市
  • 广东省

  • 韶关市
  • 广西壮族自治区

  • 北海市
  • 广西壮族自治区

  • 南宁市
  • 广西壮族自治区

  • 崇左市
  • 广西壮族自治区

  • 来宾市
  • 广西壮族自治区

  • 柳州市
  • 广西壮族自治区

  • 桂林市
  • 广西壮族自治区

  • 梧州市
  • 广西壮族自治区

  • 河池市
  • 广西壮族自治区

  • 玉林市
  • 广西壮族自治区

  • 百色市
  • 广西壮族自治区

  • 贵港市
  • 广西壮族自治区

  • 贺州市
  • 广西壮族自治区

  • 钦州市
  • 广西壮族自治区

  • 防城港市
  • 新疆维吾尔自治区

  • 乌鲁木齐市
  • 新疆维吾尔自治区

  • 伊犁哈萨克自治州
  • 新疆维吾尔自治区

  • 克孜勒苏柯尔克孜自治州
  • 新疆维吾尔自治区

  • 克拉玛依市
  • 新疆维吾尔自治区

  • 博尔塔拉蒙古自治州
  • 新疆维吾尔自治区

  • 吐鲁番市
  • 新疆维吾尔自治区

  • 和田地区
  • 新疆维吾尔自治区

  • 哈密市
  • 新疆维吾尔自治区

  • 喀什地区
  • 新疆维吾尔自治区

  • 塔城地区
  • 新疆维吾尔自治区

  • 巴音郭楞蒙古自治州
  • 新疆维吾尔自治区

  • 昌吉回族自治州
  • 新疆维吾尔自治区

  • 自治区直辖县级行政区划
  • 新疆维吾尔自治区

  • 阿克苏地区
  • 新疆维吾尔自治区

  • 阿勒泰地区
  • 江苏省

  • 南京市
  • 江苏省

  • 南通市
  • 江苏省

  • 宿迁市
  • 江苏省

  • 常州市
  • 江苏省

  • 徐州市
  • 江苏省

  • 扬州市
  • 江苏省

  • 无锡市
  • 江苏省

  • 泰州市
  • 江苏省

  • 淮安市
  • 江苏省

  • 盐城市
  • 江苏省

  • 苏州市
  • 江苏省

  • 连云港市
  • 江苏省

  • 镇江市
  • 江西省

  • 上饶市
  • 江西省

  • 九江市
  • 江西省

  • 南昌市
  • 江西省

  • 吉安市
  • 江西省

  • 宜春市
  • 江西省

  • 抚州市
  • 江西省

  • 新余市
  • 江西省

  • 景德镇市
  • 江西省

  • 萍乡市
  • 江西省

  • 赣州市
  • 江西省

  • 鹰潭市
  • 河北省

  • 保定市
  • 河北省

  • 唐山市
  • 河北省

  • 廊坊市
  • 河北省

  • 张家口市
  • 河北省

  • 承德市
  • 河北省

  • 沧州市
  • 河北省

  • 石家庄市
  • 河北省

  • 秦皇岛市
  • 河北省

  • 衡水市
  • 河北省

  • 邢台市
  • 河北省

  • 邯郸市
  • 河南省

  • 三门峡市
  • 河南省

  • 信阳市
  • 河南省

  • 南阳市
  • 河南省

  • 周口市
  • 河南省

  • 商丘市
  • 河南省

  • 安阳市
  • 河南省

  • 平顶山市
  • 河南省

  • 开封市
  • 河南省

  • 新乡市
  • 河南省

  • 洛阳市
  • 河南省

  • 漯河市
  • 河南省

  • 濮阳市
  • 河南省

  • 焦作市
  • 河南省

  • 省直辖县级行政区划
  • 河南省

  • 许昌市
  • 河南省

  • 郑州市
  • 河南省

  • 驻马店市
  • 河南省

  • 鹤壁市
  • 浙江省

  • 丽水市
  • 浙江省

  • 台州市
  • 浙江省

  • 嘉兴市
  • 浙江省

  • 宁波市
  • 浙江省

  • 杭州市
  • 浙江省

  • 温州市
  • 浙江省

  • 湖州市
  • 浙江省

  • 绍兴市
  • 浙江省

  • 舟山市
  • 浙江省

  • 衢州市
  • 浙江省

  • 金华市
  • 海南省

  • 三亚市
  • 海南省

  • 三沙市
  • 海南省

  • 儋州市
  • 海南省

  • 海口市
  • 海南省

  • 省直辖县级行政区划
  • 湖北省

  • 十堰市
  • 湖北省

  • 咸宁市
  • 湖北省

  • 孝感市
  • 湖北省

  • 宜昌市
  • 湖北省

  • 恩施土家族苗族自治州
  • 湖北省

  • 武汉市
  • 湖北省

  • 省直辖县级行政区划
  • 湖北省

  • 荆州市
  • 湖北省

  • 荆门市
  • 湖北省

  • 襄阳市
  • 湖北省

  • 鄂州市
  • 湖北省

  • 随州市
  • 湖北省

  • 黄冈市
  • 湖北省

  • 黄石市
  • 湖南省

  • 娄底市
  • 湖南省

  • 岳阳市
  • 湖南省

  • 常德市
  • 湖南省

  • 张家界市
  • 湖南省

  • 怀化市
  • 湖南省

  • 株洲市
  • 湖南省

  • 永州市
  • 湖南省

  • 湘潭市
  • 湖南省

  • 湘西土家族苗族自治州
  • 湖南省

  • 益阳市
  • 湖南省

  • 衡阳市
  • 湖南省

  • 邵阳市
  • 湖南省

  • 郴州市
  • 湖南省

  • 长沙市
  • 甘肃省

  • 临夏回族自治州
  • 甘肃省

  • 兰州市
  • 甘肃省

  • 嘉峪关市
  • 甘肃省

  • 天水市
  • 甘肃省

  • 定西市
  • 甘肃省

  • 平凉市
  • 甘肃省

  • 庆阳市
  • 甘肃省

  • 张掖市
  • 甘肃省

  • 武威市
  • 甘肃省

  • 甘南藏族自治州
  • 甘肃省

  • 白银市
  • 甘肃省

  • 酒泉市
  • 甘肃省

  • 金昌市
  • 甘肃省

  • 陇南市
  • 福建省

  • 三明市
  • 福建省

  • 南平市
  • 福建省

  • 厦门市
  • 福建省

  • 宁德市
  • 福建省

  • 泉州市
  • 福建省

  • 漳州市
  • 福建省

  • 福州市
  • 福建省

  • 莆田市
  • 福建省

  • 龙岩市
  • 西藏自治区

  • 山南市
  • 西藏自治区

  • 拉萨市
  • 西藏自治区

  • 日喀则市
  • 西藏自治区

  • 昌都市
  • 西藏自治区

  • 林芝市
  • 西藏自治区

  • 那曲市
  • 西藏自治区

  • 阿里地区
  • 贵州省

  • 六盘水市
  • 贵州省

  • 安顺市
  • 贵州省

  • 毕节市
  • 贵州省

  • 贵阳市
  • 贵州省

  • 遵义市
  • 贵州省

  • 铜仁市
  • 贵州省

  • 黔东南苗族侗族自治州
  • 贵州省

  • 黔南布依族苗族自治州
  • 贵州省

  • 黔西南布依族苗族自治州
  • 辽宁省

  • 丹东市
  • 辽宁省

  • 大连市
  • 辽宁省

  • 抚顺市
  • 辽宁省

  • 朝阳市
  • 辽宁省

  • 本溪市
  • 辽宁省

  • 沈阳市
  • 辽宁省

  • 盘锦市
  • 辽宁省

  • 营口市
  • 辽宁省

  • 葫芦岛市
  • 辽宁省

  • 辽阳市
  • 辽宁省

  • 铁岭市
  • 辽宁省

  • 锦州市
  • 辽宁省

  • 阜新市
  • 辽宁省

  • 鞍山市
  • 重庆市

  • 重庆市

  • 市辖区
  • 陕西省

  • 咸阳市
  • 陕西省

  • 商洛市
  • 陕西省

  • 安康市
  • 陕西省

  • 宝鸡市
  • 陕西省

  • 延安市
  • 陕西省

  • 榆林市
  • 陕西省

  • 汉中市
  • 陕西省

  • 渭南市
  • 陕西省

  • 西安市
  • 陕西省

  • 铜川市
  • 青海省

  • 果洛藏族自治州
  • 青海省

  • 海东市
  • 青海省

  • 海北藏族自治州
  • 青海省

  • 海南藏族自治州
  • 青海省

  • 海西蒙古族藏族自治州
  • 青海省

  • 玉树藏族自治州
  • 青海省

  • 西宁市
  • 青海省

  • 黄南藏族自治州
  • 黑龙江省

  • 七台河市
  • 黑龙江省

  • 伊春市
  • 黑龙江省

  • 佳木斯市
  • 黑龙江省

  • 双鸭山市
  • 黑龙江省

  • 哈尔滨市
  • 黑龙江省

  • 大兴安岭地区
  • 黑龙江省

  • 大庆市
  • 黑龙江省

  • 牡丹江市
  • 黑龙江省

  • 绥化市
  • 黑龙江省

  • 鸡西市
  • 黑龙江省

  • 鹤岗市
  • 黑龙江省

  • 黑河市
  • 黑龙江省

  • 齐齐哈尔市