Chinaunix首页 | 论坛 | 博客
  • 博客访问: 465827
  • 博文数量: 724
  • 博客积分: 40000
  • 博客等级: 大将
  • 技术积分: 5010
  • 用 户 组: 普通用户
  • 注册时间: 2008-10-13 14:47
文章分类

全部博文(724)

文章存档

2011年(1)

2008年(723)

我的朋友

分类:

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, 暂不确定它到底是何类型
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  //模板参数声明中时, class与typename同义
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 root; //将type确定为int, 并定义这个特化类的一个实例;
尝试这样做.

node char_root;
node short_root;
node long_root;

print("%d:%d:%d", sizeof(char_root.value),
                  sizeof(short_root.value),
                  sizeof(long_root.value));
结果应该是 1:2:4. 说明value的确是我们想要的那个类型.

如果嫌使用时指定模板参数太麻烦的话, 可以使用typedef
typedef node char_node_t;
typedef node char_node_t;
typedef node long_node_t;

long_node_t root;

需要说一下的是, 模板本身不是一个类型; 如果相同模板, 模板参数不同时, 那么特化出来的类型绝不是
同一类型. 即这样做是错误的

char_node_t* root = new long_node_t;

下面给出一个稍复杂的类模板定义

template //如同函数参
                                                                     //数一样, 模
                                                                     //板参数也可
                                                                     //以声明默认
                                                                     //参数
class bidirect_list
{
public:
    typedef node node_type;
   
    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;
};

下一回将会说说: 模板的特化版本定义.


--------------------next---------------------

阅读(196) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~