模板类类模板
时间:2023-02-19 12:40:02 | 来源:营销百科
时间:2023-02-19 12:40:02 来源:营销百科
模板类类模板:类模板(class templates)可以使用类模板创建对一个类型进行操作的类家族。
template class T, int i // 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))
模板:
templateclass T
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 T, int i class MyStack
{
T StackBuffer[i];
int cItems;
public:
void MyStack( void ) : cItems( i ) {};
void push( const T item ); T pop( void );
};
template class T, int i void MyStack T, i ::push( const T item )
{
if( cItems 0 ) StackBuffer[--cItems] = item;
else throw 'Stack overflow error.';
return;
}
template class T, int i T MyStack T, i ::pop( void )
{
if( cItems i )
return StackBuffer[cItems ];
else throw 'Stack underflow error.';
}
模板和 智能指针(Templates and Smart Pointers)
C 允许你创建' 智能指针'('smart pointer')类囊括指针和 重载指针操作符来为指针操作增加新的功能。模板允许你创建普通包装来囊括几乎所有类型的 指针。
如下的代码概括了一个简单的计数垃圾收集者参考。模板类PtrT为任何从RefCount继承的类实现了一个垃圾收集 指针。
#include stdio.h
#define TRACE printf
class RefCount
{
int crefs;
public:
RefCount(void) { crefs = 0; }
~RefCount() { TRACE('goodbye(%d)n', crefs);}
void upcount(void)
{
crefs;
TRACE('up to %dn', crefs);
}
void downcount(void)
{
if (--crefs == 0) { delete this; }
else TRACE('downto %dn', crefs);
}
};
class Sample : public RefCount
{
public:
void doSomething(void) { TRACE('Did somethingn');}
};
template class T 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=(PtrT p_) {return operator=((T *) p_);}
Ptr operator=(T* p_) { p-downcount(); p = p_; p-upcount(); return *this; }
};
int main()
{
PtrSample p = new Sample;
// sample #1 PtrSample 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 和 PtrT共同为任何一个从RefCount继承的能够提供整数的类的每一个实例提供了一个简单的垃圾收集解决方案。注意使用一个参数类如PtrT代替多个一般类如Ptr的主要好处在于这种形式是完全的 类型安全的。前面的代码保证PtrT可以被用在几乎任何T* 使用的地方;相反,一个普通类Ptr只能提供到void*固有的转换。
例如,考虑一个用来创建和处理文件垃圾收集的类,符号、字符串等等。根据类模板PtrT,编译器可以创建模板类PtrFile,PtrSymbol, PtrString等等,和它们的成员函数:PtrFile::~Ptr(), PtrFile::operator File*(), PtrString::~Ptr(), PtrString::operator String*()等等。