一·C++提供了模版的编程方法来解决编程问题,思路是:程序员先编号一份“套路”代码,然后在调用时编译器根据调用时的参数
再为这种数据类型生成一份属于他的代码
C语言中的快速排序:
void qsort(void *base, size_t nmemb, size_t size,int(*compar)(const void *, const void *))
二.模板的语法
template <typename T,typename M>
T max(T num1,M num2)
{
return num1>num2?num1:num2;
}
a.模版的类型参数
T 被称为模版的类型参数,可以叫任何名字,只是俗称约定叫做T
它指的是函数调用时的任意类型的参数
虽然模版的类型可以是任意的,但是必须要支持模版函数中所使用到的运算符,模版不是万能的,虽然能带来好处
但也带来了很多问题
b.函数模版的使用
1. 模版的实例化
编译器不会把函数模版编译成一个实例,而是根据调用的参数在进行实例化(进一步生成二进制指令)。
2. 使用模版时才实例化
模版只有在调用时才会实例化,因此模版编译正确并不代表没有问题,很多错误会产生在调用时
3. 二次编译
第一次编译是检查模版的语法,第二次是根据参数把模版实例化出来,再检查运算符是否支持这种类型。
下面是用模板实现的冒泡排序,能够被所有数据类型调用
三.函数模版的隐式推断
a. 使用函数模版时可以根据参数的类型来推断模版的参数
b. 当函数模版不能通过函数调用时的参数来判断模版函数是,可以使用<类型,类型........> 来明确指定
c.函数模版参数是可以有默认值的,
1. 默认值要优先放在右边
2. C++标准才支持:-std=c++0x
四.函数模版与普通函数可以重载(特化)
1. 同一种格式的函数和函数模版是可以共生的,但是优先调用普通函数,但是可以有函数名后添加一个空的<>指定调用函数模版
模版参数可以根据调用时的参数推断
2. 普通函数在调用时可以进行类型提升,但是这种提升要低于模版的实例化;
3. 函数模版也可以进行类型提升,但如果有一个普通函数也可以进行类型提升调用,那么优先调用普通函数
五.类模块
a.类模版的语法
类模版的参数可以在类中当作类型使用,可以定义成员,返回值,参数等
template<class T,class A,class B...>
class className
{
C c;
public:
T func(A a);
}
注意:typename也可以继续使用,但大多数用class以示区别
b.类模版的使用
类模版必须要经过实例化才能使用,也是需要经过两次编译,第一次是把类模版编译成一个“套路”,这个过程是未来检查
语法,第二次是根据实例化参数,生成一个类,然后才能使用这个类创建对象
使用类模版实例化一个类:
className<type1,type2...> a;
c.类模版参数不支持隐式推断,必须显示实例化
d.静态成员的定义
template <class T> int classname<T>::num = 10;
静态成员必须在类模版实例化后才被正真定义出来,每个实例化的类都有一份静态成员,这个实例化类创建出的
对象公用一个静态成员
e.递归实例化
classname<classname<int>> 对象
六.类模版的特化(重载)
特化:当类模版不能特殊的类型无法处理时,可以为这种特殊类型单独实例化一个类,这个单独的实现叫做模版的特化
全类的特化:按照类的格式把类完整的实现一遍(重写一遍)
template <> class className <返回值类型>
{
......
};
成员特化:给制定类型提供一个特殊的成员函数
template <> 返回值类型 className<返回值类型>:max(void)
{
....
}
局部特化:可以让用户根据实例化时的参数来指定所使用的类模版
同等程度的特化会产生二异性
七.类模版的参数
1. 类模版的参数可以有默认值
注意:使用类模版默认值时,<>必须加上,可以空着,但不能不写
2. 类模版后面的参数可以调用前边的参数
3. 普通数值可以对类模版进行实例化,它必须以类似变量的形式存在
注意:只能常量才能进行实例化,