分类:
2008-10-13 17:06:14
模板是C++最后添加的一个重要的组成部分. 它使C++编程理念进行一次革命, 产生泛型编程方法.
泛型编程(generic programming), 从名字上来看就是与类型无关的进行编程的方法.
从感性上感受的话, 的确是这样的, 不过不仅局限如此.
模板的官方定义是这样的:
a template define a family of classes or functions. //一个模板, 就是定义一组类或函数
一个模板定义形式就是这样的
template < template-parameter-list > declaration
template-parameter-list:
template-parameter
template-parameter-list, template-parameter;
好, 掉书包就到此为止.
如是说:"所有的工具都是为了解决问题的而发明出来的."
那么模板是为了解决什么问题而设计出来的呢?
那么, 举这么一个简单的例子吧.
我想实现一个比较大小的函数, 这个函数将返回两个参数中最大值. 它要求应该支持所有的数值类型.
想想这个函数应该怎么写呢?
long max(long a, long b)
{
return (a>b)?a:b;
}
unsigned long max(unsigned long a, long b)
{
return (a>b)?a:b;
}
double max(double a, double b)
{
return (a>b)?a:b;
}
介个是最简约的写法了. 针对不同类型, 我一下要写三个函数, 但它们的代码是相同的. 这还是一个比较
简单的例子. 如果倘如更复杂的情况下, 我们不得不一下写出相同内容的代码来. 比如日志工具类, 它不
光要将普通类型进行记录, 还需要将你的类对象导出成一种可读的信息. 这是一场灾难.
针对上面的例子来说, 可以有一个比较简单的解决方案 - 使用宏:
#define max(a, b) ((a>b)?a:b)
这样就可以比较容易解决了类型的问题.
但这种方法仍有一不完美的地方, 那就是它不是一个函数. 在编译的时候, 它是将代码进行替换. 当大量
使用这种解决方案的话, 生成代码将会越来越大. 另外在特殊要求的情况, 比如:通过函数指针来进行函
数调, 它将无能为力了.
这样就需要利用模板了, 可以通过模板把类型进行抽象.
template
type max(type a, type b)
{
return (a>b)?a:b;
}
上面的模板定义, 将参数类型和返回类型抽象成type, 这个type叫做模板的参数. 或者可以这样说.
template
type max(type a, type b) //函数的返回值和参数 均为type
{
return (a>b)?a:b;
}
当我们使用这个max时,
int a = 12, b = 99;
int result = max(a, b);
编译器通过分析, 知道这个max调用的返回类型和参数类型. 它会通过模板定义, 来确定模板参数type到
底是何类型. 哦, 这回是int. 那么编译器会首先将模板进行特化(specialize)为
int max(int a, int b)
{
return (a>b)?a:b;
}进行编译. 这时, 我们就有了int max(int a, int b);这个函数了.
编译器然后就将max(a, b);调用将向模板特化版本的地址.
这个就是stl中的max模板的定义
template
const Type& max(const Type& _Left, const Type& _Right);
上面这是一个函数模板的例子.
下面就再说一个类模板的定义
做一个双向整型链表. 那么结点的定义是什么呢?
struct node //在C++中class和struct是一回事, 只不过默认的成员访问权限不同
{
node* prev;
node* next;
int value;
};
类似于函数模板的方法可以定义一个泛型的结点定义
template
struct node
{
node* prev;
node* next;
type value;
};
与函数模板不同的是, 在使用类模板时需要明确地给个模板参数的类型.
node
尝试这样做.
node
node
node
print("%d:%d:%d", sizeof(char_root.value),
sizeof(short_root.value),
sizeof(long_root.value));
结果应该是 1:2:4. 说明value的确是我们想要的那个类型.
如果嫌使用时指定模板参数太麻烦的话, 可以使用typedef
typedef node
typedef node
typedef node
long_node_t root;
需要说一下的是, 模板本身不是一个类型; 如果相同模板, 模板参数不同时, 那么特化出来的类型绝不是
同一类型. 即这样做是错误的
char_node_t* root = new long_node_t;
下面给出一个稍复杂的类模板定义
template
//数一样, 模
//板参数也可
//以声明默认
//参数
class bidirect_list
{
public:
typedef node
bidirect_list()
{
head.prev = NULL;
head.next = NULL;
}
bidirect_list(int value)
{
head.prev = NULL;
head.next = NULL;
append(value);
}
void clear()
{
node_type* last = head.prev, *temp;
while(last && (last != &head))
{
temp = last;
last = last->prev;
delete temp;
}
}
node_type* head()
{
return &head;
}
node_type* tail()
{
return (head.prev)?head.prev:&head;
}
void remove(node_type* node)
{
if (node == NULL || node == &head)
return;
if (node->prev != NULL)
node->prev->next = node->next;
if (node->next != NULL)
node->next->prev = node->prev;
}
void append(value_type value)
{
node_type* the_tail = tail();
the_tail->next = new node_type;
the_tail->next->next = NULL;
the_tail->next->prev = the_tail;
the_tail->next->value = value;
head->prev = the_tail->next;
}
void insert(node_type* node, value_type value)
{
if (node == NULL)
return;
node->next = new node_type;
node->next->prev = node;
node->next->next = NULL;
node->next->value = value;
if (node == tail())
head->prev = node->next;
}
static value_type& get_value(node_type* node)
{
static value_type temp;
return (node != NULL)?node->value:temp;
}
static node_type* next_node(node_type* node)
{
return (node != NULL)?node->next:NULL;
}
static node_type* prev_node(node_type* node)
{
return (node != NULL)?node->prev:NULL;
}
private:
node_type head;
};
下一回将会说说: 模板的特化版本定义.