1、类的模板的使用
类,由于没有参数,所以没有模板实参推导机制。
 #include <stdexcept>

 template<typename T> class my_stack;

 template<typename T>
class list_node
{
T value;
list_node *next; list_node(T const &v, list_node *n) :
value(v), next(n){} friend class my_stack<T>;
}; template<typename T>
class my_stack
{
typedef list_node<T> node_type;
node_type *head; my_stack operator=(my_stack const&);
my_stack(my_stack const &s){} public:
my_stack() :head(){}
~my_stack()
{
while (!empty())
pop();
} bool empty(){ return head == ; }
T const& top() const throw(std::runtime_error)
{
if (empty())
{
throw std::runtime_error("Stack is empty");
}
return head->value;
} void push(T const &v)
{
head = new node_type(v, head);
} void pop();
}; template<typename T>//类成员函数的实现同样要放在和类声明相同的头文件里
void my_stack<T>::pop()
{
if (head)
{
node_type* tmp = head;
head = head->next;
delete tmp;
}
}
2、模板类的继承
 
 template<typename T>
class count_stack : public my_stack<T>
{
typedef my_stack<T> base_type;
unsigned size; public:
count_stack() :base_type(), size(){}
void push(T const &v)
{
base_type::push(v);
size++;
} void pop()
{
if (size > )
{
base_type::pop();
size--;
}
} unsigned getSize() const { return size; }
};

如果是普通类以模板实例为基类,需要为基类模板给定明确的模板参数值。例如,

class another_stack:public my_stack<char>{}
 
3、异质链表
链表的类型为固定指向另一个类型节点的类,这就约束了链表中节点必须是同一类型,从而整个链表只能保存同一类型的数据。模板的一个特殊功能就是可以构造异质链表。构造的思路是以嵌套的形式,一会会进行演示。
 
这里只涉及到了异质链表的节点:
 template<typename T, typename N>
struct hetero_node
{
T value;
N* next;
hetero_node(T const &v, N *n) :value(v), next(n){}
}; template<typename T, typename N>
hetero_node<T, N>* push(T const &v, N *n)
{
return new hetero_node<T, N>(v, n);
} template<typename T, typename N>
N* pop(hetero_node<T, N> *head)
{
N *next = head->next;
delete head;
return next;
}
使用异质链表结构构造三元组:
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(, (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(, '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 = ; void call1()
{
the_class<int> c;
printf("static id:%d\n", c.id);
} void call2()
{
the_class<int> c;
printf("static id:%d\n", c.id);
}
输出结果:

编译call1.cpp和call2.cpp会生成两个the_class的实例,会拥有两个the_class<int>::id的分配内存地址,但是在链接时,链接器将随机选择一个目标中的空间作为最终的存储空间,从而使不同目标文件中的多个等价模板实例共享同一套静态成员存储空间。
 
 
 

《深入实践C++模板编程》之二——模板类的更多相关文章

  1. 《深入实践C++模板编程》之三——模板参数类型详解

    非类型模板参数 和 模板型模板参数 整数以及枚举类型:指向对象或者函数的指针:对对象或函数的引用:指向对象成员的指针.统称为非类型模板参数. 模板型模板参数,是指模板参数还可以是一个模板.   1.整 ...

  2. JavaScript 面向对象的编程(二) 类的封装

    类的定义 方式一 var Book = function(id, name, price){ //私有属性,外部不能直接访问 var num = 1; //私有方法, function checkId ...

  3. Scala 编程(二)类和对象

    类,字段和方法 类是对象的蓝图.一旦定义了类,就可以用关键字new从类的蓝图里创建对象,类的定义: class ChecksumAccumulator { // class definition go ...

  4. Django模板的继承与模板的导入

    目录 一:模版的继承 1.什么是模板继承? 2.使用继承流程原理 3.模板继承语法 二:模板的继承使用 1.案例需求 2.总结模板继承 三:模版的导入 1.模板导入 2.模板导入格式 3.模板导入使用 ...

  5. 《深入实践C++模板编程》之四——特例

    1. 所谓模板特例,是针对符合某种条件的模板参数值集合另外声明的模板实现变体. template<typename T> class my_vector; template<> ...

  6. 《深入实践C++模板编程》之一——Hello模板

    1.通过一个简单的例子来理解模板的用途: 模板为不同类型的数据生成操作相同或相似的函数. 弱语言如Python,可以使用一种函数来应对各种类型,但是C++就不得不为不同的类型编写相似的函数.模板的作用 ...

  7. C++ 11可变参数接口设计在模板编程中应用的一点点总结

    概述 本人对模板编程的应用并非很深,若要用一句话总结我个人对模板编程的理解,我想说的是:模板编程是对类定义的弱化. 如何理解“类定义的弱化”? 一个完整的类有如下几部分组成: 类的名称: 类的成员变量 ...

  8. C++模板编程中只特化模板类的一个成员函数

    模板编程中如果要特化或偏特化(局部特化)一个类模板,需要特化该类模板的所有成员函数.类模板中大多数成员函数的功能可能是一模一样的,特化时我们可能只需要重新实现1.2个成员函数即可.在这种情况下,如果全 ...

  9. C++之模板编程

    当我们越来越多的使用C++的特性, 将越来越多的问题和事物抽象成对象时, 我们不难发现:很多对象都具有共性. 比如 数值可以增加.减少:字符串也可以增加减少. 它们的动作是相似的, 只是对象的类型不同 ...

随机推荐

  1. Ubuntu 安装 JDK1.8

    以下是Ubuntu 14.04安装JDK1.8.0_25与配置环境变量过程笔记. 1.源码包准备: 首先到官网下载jdk,http://www.oracle.com/technetwork/java/ ...

  2. Android APP切换到后台接收不到推送消息

    1.   Android端进程被杀死后,目前自带的保护后台接收消息活跃机制.暂时没有什么好的机制保持任何情况下都活跃 android原生系统用home键杀进程可以起来,如果是强行停止就只能用户自己手动 ...

  3. RCAN——Image Super-Resolution Using Very Deep Residual Channel Attention Networks

    1. 摘要 在图像超分辨领域,卷积神经网络的深度非常重要,但过深的网络却难以训练.低分辨率的输入以及特征包含丰富的低频信息,但却在通道间被平等对待,因此阻碍了网络的表示能力. 为了解决上述问题,作者提 ...

  4. easyUI之Accordion(分类)

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <hea ...

  5. UnicodeEncodeError: 'ascii' codec can't encode characters

    将网页get到之后输入文本出现UnicodeEncodeError: 'ascii' codec can't encode characters错误 f = open('re.txt', 'w') u ...

  6. 用python读取csv信息并写入新的文件

    import csv fo = open("result.txt", "w+") reader = csv.reader(open('test.csv')) f ...

  7. [转]SQL server 2008R2 中 C#Winfoirm 使用 SqlDependency 机制实现 数据库中某一张表的监视

    转自:https://blog.csdn.net/u012183487/article/details/77776930 System.Data.SqlClient命名空间下的 sqlDependen ...

  8. Oracle面试题

    0.绑定变量的优缺点及使用场合分别是什么? 优点:能够避免SQL的硬解析以及与之相关的额外开销(SQL语法.语义的分析.逻辑分析.生成较佳的执行计划等开销),提高执行效率. 缺点:如果在表存在数据倾斜 ...

  9. c/c++编码规范(2)--作用域

    2. 作用域 静止使用class类型的静态或全局变量. 6. 命名约定 6.1. 函数名,变量名,文件名要有描述性,少用缩写. 6.2. 文件命名 6.2.1. 文件名要全部用小写.可使用“_”或&q ...

  10. k8s nginx-ingress 504 timeout

    nginx ingress 报错 504 timeout,是由于反向代理超时造成的,反向代理默认超时时间60s 官方文档 配置片段: apiVersion: extensions/v1beta1 ki ...