模板和泛型编程
模板:另一种多态性的体现
函数模板
函数体完全类似,只是形参类型不同
Template<typenameT>:模板形参(类型形参)T
接受到可以的类型实参后,编译器生成对应的函数
类模板
Template<classT>
用T来代表成员函数需要的类型
ConstT& function(const T&a);
使用时: 要显示的指定模板形参 Myqueue<int> q;
编译过程: 用户传模板实参,编译器根据参数定制出一个特定的类
细节
模板形参变量在模板结束后失效,同时会屏蔽外部变量。就像函数形参一样
模板形参的名字:不能在内部重用,且不能出现同名
类型形参: 前面加上class,typename,非类型: 前加上类型
Typename: 显示的调用以告诉编译器后面的内容是一个类型
TypenameT::value_type//T是一个迭代器类型形参
非类型形参:调用时会用值代替,典型:数组长度
尽量减少对类型的要求:使得模板能对尽量多的类型都适用,const(允许不可复制类型)和只使用<(不要求>)是一种良好的习惯
实例化
模板实例化出特定的函数或者类。编译器自动实现。
模板参数:在提供给类模板参数后才定义出具体的类。必须显示<>提供给类模板
函数模板: 编译器会根据函数实参推断模板实参。必须要完全匹配
非模板函数:隐式转换实参,模板函数:实例化新的函数
const转换
非引用: 数组和函数转为指针
参数类型不匹配:1.强制转换static_cast<int>shorta
2.显式实例化函数<>,可以从右往左省略:实例化之后函数参数会发生隐式转化
模板编译模型
普通情况
头文件:类定义,普通函数声明
源文件:类成员函数定义,普通函数定义
模板:
1. 包含编译模型:在.h中除了类定义,函数声明,还include对应的定义.c
如此等于实现文件在.h文件里,但为了.h不过于长应该区分它们
2. 分别编译:.h里只写函数声明或类定义,在定义处加上export template<typename T> …
内联函数:写在类.h里,static写在定义里
类模板成员
类定义:除了要加上template<typenameT>和往常一样
类成员定义:每个都要加上template<typenameT> 返回类型 class<类型参数>::function_name (参数)
类成员实例化:类型自动由类推断,在调用时实例化后接受参数(更加灵活,允许隐转)
函数不用不实例化,指针定义不实例化,指针使用时实例化。
非类型形参: 在编译时需要一个常量const,且类型要和模板定义一致
友元
1. 普通函数、类
2 模板的所有实例 friend/inline等关键字要出现的template后,且这些友元模板要 使用和类不用的模板形参变量
3 模板的某些实例 显示给定模板参数使模板实例化(或是使用相同的模板参数变量T)。要在之前声明为是模板。
成员模板
模板类的成员函数:由类的模板参数推断而来的模板
成员模板: 不依赖类的模板参数列表。有自己的template<typenameQ>
为了可以接受更多类型的函数参数
定义: template<typename T>//类模板参数
Template<typenameQ>//函数模板参数
VoidQueue<T>::function(Q &a)
{}
一个泛型句柄类
句柄类:管理对象指针和智能计数
一个T对象指针ptr,一个size_t计数指针use
构造,拷贝构造,赋值操作符,析构(都要改变*use的值)
*,->操作符(好似使用指针一样使用句柄对象)
一个基于Handle的句柄类:
一个具体的Handle对象 Handle<classname> h
不需要复制控制:成员没有指针,其行为都依赖h完成了
重载*,->: 使用h的*,->
良好的编码: 在重构实现时不要改变其接口函数(public,protect)