C++学习随笔12 面向对象编程(5)- 模板

  • 函数模板
  1. 函数模板定义:

template <类型参数表>            //每个模板形参都必须加上前缀typename

返回类型  函数模板名(数据参数表)

{

  函数模板定义体

}

函数模板不是函数,它是以具体的类型为实参来生成函数体的模板。函数模板定义被编译时,不会产生任何执行代码。 

       2. 函数模板用法:

使用函数模板,就是以函数模板名为函数名的函数调用,其形式为:

    函数模板名(数据实参表);

第一次使用函数模板时,会触发编译器产生一个对应函数模板的函数体定义。(函数模板的实例化)

 1 template<typename T>
 2 void swap(T& a, T& b)
 3 {
 4       T temp = a; a = b; b = temp;
 5 }
 6 
 7 
 8 int main(){
 9     double dx = 3.5, dy = 5.6;
10     int ix = 6, iy = 7;
11     swap(dx, dy);              //生成模板函数swap<double>
12     swap(ix, iy);              //生成模板函数swap<int>
13 }                              //它们并不是重载函数,因为其函数名称各不相同

         3. 函数模板的参数:

函数模板的类型参数没有隐式转换之说,必须精确匹配。对于调用中的几个数据实参类型不同,而数据形参类型却要求相同时,用显示模板类型指定的方法是必须的,否则模板参数将拒绝匹配。

 1 template <typename T>
 2 T const& max(T const& a, T const& b){
 3        return a < b ? b : a;
 4 }
 5 
 6 int main(){
 7     int ia = 3;
 8     double db = 5.0;
 9     cout<<max<double>(ia, db)<<"\n";              //max<double>确定了模板函数名,使其成为普通函数,从而让int隐式转化为double
10     cout<<max(static_cast<double>(ia), db)<<"\n"; //预先将数据实参转化为所需类型
11 }

对于引用型形参,要求数据实参不能是常量或字面值。

         4. 函数模板的重载:

模板机制规定,如果一个调用既匹配普通函数,又匹配模板函数,则先匹配普通函数。

 1 template <typename T>
 2 T const& max(T const& a, T const& b){
 3         return a < b ? b : a;
 4 }
 5 //函数模板重载
 6 template <typename T>
 7 T* const& max(T* const& a, T* const& b){            //T* const&,即T*的const引用;  const T*&,即const T*类型的引用
 8         return *a < *b ? b : a;
 9 }
10 //max函数重载
11 const char* const& max(const char* const& a, const char* const& b){
12       return std::strcmp(a, b) < 0 ? b : a;
13 }
14 
15 int main(){
16    int ia = 3, ib = 7;
17    char* s1="hello";
18    char* s2 = "hell";
19    cout<<*max(&ia, &ib)<<"\n";   //匹配第二个模板,若没有函数模板重载,max(&ia, &ib)将int *匹配成T,比较的是两个指针的大小
20    cout<<max(s1, s2)<<"\n";      //匹配max函数
21    cout<<max(ia, ib)<<"\n";      //匹配第一个模板
22 }
  • 类模板
  1. 模板类和类模板:

类模板是一种模板。类模板名简称模板名,如“template<typename T>class List”中的List。模板类一般指从类模板产生的类。模板类名表示为模板名后跟带尖括号的类型实参表,如“List<double> dList;“中的List<double>为模板类名。类模板不是类,而模板类是类。

      2. 模板实例化:

只实例化类模板的定义部分,不将其成员函数的定义部分一起实例化,直到后面首次遇到模板类成员函数的调用时,才进行类模板的成员函数的实例化。也可以通过显示实例化方式马上将所有的类模板的成员函数都实例化成对应的模板成员函数。

 1 int main(){
 2     template List<double>;           //显示实例化
 3     template List<int>;              //显示实例化
 4     List<double> dList;
 5     dList.add(3.6);                  //因为已经显示实例化,不再单独实例化
 6     dList.print();
 7     List<int> iList;
 8     iList.add(5);
 9     iList.print();
10 }

      3. 程序组织:

包含方式:将模板的整个定义都放在头文件中。如果是函数模板,需要一个函数模板定义;如果是类模板,需要将类模板定义和类模板的成员函数定义一并写入头文件中。

分离方式:将模板函数声明和模板函数定义分离,将类模板定义与类模板实现分离,分别写入.h和.cpp文件中,但是在模板声明和模板定义的template关键字前加export关键字。

      4. 模板的多态:

1 template<typename T>
2 void fn(const T& a){
3      cout<<a.area();
4 }
5 
6 void g(Circle x, Rectangle y){  //当函数g的fn调用中,实参为Circle及Rectangle的对象时,其表现的area行为是不同的,一个求圆面积,一个求长方形面积
7      fn(x);
8      fn(y);
9 }

模板的多态不是在运行中进行动态识别的(动多态),而是在编译时刻进行静态识别的(静多态)。

posted @ 2016-12-13 11:08  etcjd  阅读(176)  评论(0)    收藏  举报