1、类的模板的使用
类,由于没有参数,所以没有模板实参推导机制。
1 #include <stdexcept> 2 3 template<typename T> class my_stack; 4 5 template<typename T> 6 class list_node 7 { 8 T value; 9 list_node *next; 10 11 list_node(T const &v, list_node *n) : 12 value(v), next(n){} 13 14 friend class my_stack<T>; 15 }; 16 17 template<typename T> 18 class my_stack 19 { 20 typedef list_node<T> node_type; 21 node_type *head; 22 23 my_stack operator=(my_stack const&); 24 my_stack(my_stack const &s){} 25 26 public: 27 my_stack() :head(0){} 28 ~my_stack() 29 { 30 while (!empty()) 31 pop(); 32 } 33 34 bool empty(){ return head == 0; } 35 T const& top() const throw(std::runtime_error) 36 { 37 if (empty()) 38 { 39 throw std::runtime_error("Stack is empty"); 40 } 41 return head->value; 42 } 43 44 void push(T const &v) 45 { 46 head = new node_type(v, head); 47 } 48 49 void pop(); 50 }; 51 52 template<typename T>//类成员函数的实现同样要放在和类声明相同的头文件里 53 void my_stack<T>::pop() 54 { 55 if (head) 56 { 57 node_type* tmp = head; 58 head = head->next; 59 delete tmp; 60 } 61 } 62
2、模板类的继承
1 template<typename T> 2 class count_stack : public my_stack<T> 3 { 4 typedef my_stack<T> base_type; 5 unsigned size; 6 7 public: 8 count_stack() :base_type(), size(0){} 9 void push(T const &v) 10 { 11 base_type::push(v); 12 size++; 13 } 14 15 void pop() 16 { 17 if (size > 0) 18 { 19 base_type::pop(); 20 size--; 21 } 22 } 23 24 unsigned getSize() const { return size; } 25 }; 26
如果是普通类以模板实例为基类,需要为基类模板给定明确的模板参数值。例如,
class another_stack:public my_stack<char>{}
3、异质链表
链表的类型为固定指向另一个类型节点的类,这就约束了链表中节点必须是同一类型,从而整个链表只能保存同一类型的数据。模板的一个特殊功能就是可以构造异质链表。构造的思路是以嵌套的形式,一会会进行演示。
这里只涉及到了异质链表的节点:
1 template<typename T, typename N> 2 struct hetero_node 3 { 4 T value; 5 N* next; 6 hetero_node(T const &v, N *n) :value(v), next(n){} 7 }; 8 9 template<typename T, typename N> 10 hetero_node<T, N>* push(T const &v, N *n) 11 { 12 return new hetero_node<T, N>(v, n); 13 } 14 15 template<typename T, typename N> 16 N* pop(hetero_node<T, N> *head) 17 { 18 N *next = head->next; 19 delete head; 20 return next; 21 } 22
使用异质链表结构构造三元组:
typedef hetero_node<int, void> node0; typedef hetero_node<char, node0> node1; typedef hetero_node<std::string, node1> node2; node2 *p2 = push(std::string("Awesome"), push('w', push(1, (void*)NULL))); pop(pop(pop(p2)));
构建链表时,一个节点的指针,就代表了整个链表,所有的操作都采用一种嵌套的形式,可以体现一种新的设计思路。
next指针占据额外的开销,有没有办法节省这种开销?
template<typename T, typename N> struct tuple { T value; N next; tuple(T const &v, N const &n) :value(v), next(n){} }; template<typename T, typename N> tuple<T, N> push(T const &v, N const &n) { return tuple<T, N>(v, n); } typedef tuple<int, char> tuple0; typedef tuple<float, tuple0> tuple1; typedef tuple<std::string, tuple1> tuple2; tuple2 t = push(std::string("test"), push(1.0f, push(1, 'a')));
当然你也可以用类来实现tuple,但是这样的元组的元素个数是固定的:
template<typename T0, typename T1, typename T2> struct tuple3 { T0 v0; T1 v1; T2 v2; tuple3(T0 const &_v0, T1 const & _v1, T2 const & _v2) : v0(_v0), v1(_v1), v2(_v2){} };
总结:异质链表摆脱具体数据类型的束缚。
4、成员函数模板
如果类是一个模板,以我们前面的my_stack为例:
template<typename T> void my_stack<T>::pop() { if (head) { node_type* tmp = head; head = head->next; delete tmp; } }
如果类不是一个模板,但成员函数是一个模板:
struct normal_class { int value; template<typename T> void set(T const &v) { value = int(v); } };
如果类和成员函数都是模板,该怎么在类外定义:
template<typename N> struct a_class_template { N value; template<typename T> void set(T const& v) { value = N(v); } template<typename T> T get(); }; template<typename N> template<typename T> T a_class_template<N>::get() { return T(value); }
5、类模板的静态成员
template<typename T> struct the_class { static int id; the_class(){ id++; } }; template<typename T> int the_class<T>::id = 0; void call1() { the_class<int> c; printf("static id:%d ", c.id); } void call2() { the_class<int> c; printf("static id:%d ", c.id); }
输出结果:
编译call1.cpp和call2.cpp会生成两个the_class的实例,会拥有两个the_class<int>::id的分配内存地址,但是在链接时,链接器将随机选择一个目标中的空间作为最终的存储空间,从而使不同目标文件中的多个等价模板实例共享同一套静态成员存储空间。