C++ 模版

背景 :

      c++ 多态可以大致分为两种:

  1. 继承(动态的多态)
  2. 模版(静态的多态)

分类  :

  1.     函数模版
  2.    类模版

 

  • 函数模版  :
// 普通函数

void Swap(int & a, int & b) {

      int tmp = a;
           a  = b ;
           b = tmp;
 }

//  函数模版

template <class T> 

void Swap( T & a , T & b) {

        T  tmp = a;
            a  = b;
            b  = tmp;
}

这样的好处一眼就能看到  :  兼容 int   double   等等的基础类型,不会显得代码冗余,在编译的时候根据我们的定义 实例化对应的函数模版

同时,template<class T1, class T2> 可以实现多种类型的参数

 

函数模版可以重载 :

// 模板函数 1
template<class T1, class T2>
void print(T1 arg1, T2 arg2) 
{
    cout<< arg1 << " "<< arg2<<endl;
}

// 模板函数 2
template<class T>
void print(T arg1, T arg2) 
{
    cout<< arg1 << " "<< arg2<<endl;
}

// 模板函数 3
template<class T,class T2>
void print(T arg1, T arg2) 
{
    cout<< arg1 << " "<< arg2<<endl;
}

根据模版参数不同实现函数重载 形参数量不同或者名字不同

 

函数模版和函数的次数关系 

在有多个函数和函数模板名字相同的情况下,编译器如下规则处理一条函数调用语句:

  1. 先找参数完全匹配的普通函数(非由模板实例化而得的函数);
  2. 再找参数完全匹配的模板函数;
  3. 再找实参数经过自动类型转换后能够匹配的普通函数;
  4. 上面的都找不到,则报错。

模版的特例化:

  1. 完全特例化
  2. 部分特例化

 

类模版 

为了更好的定义一系列具有相同功能的类 ,可以定义类模版,由类模版生成不同的类

template<typename T>  //  也可使用 template<class T>
  class A {
  public :
   A()  {}
   ~A() {}
   private:
  T * _ptr;
  T count;
}; 

 

函数模版作为类模版的成员

当函数模板作为类模板的成员函数时,是可以单独写成函数模板的形式,成员函数模板在使用的时候,编译器才会把函数模板根据传入的函数参数进行实例化,例子如下:

/ 类模板
template <class T>
class A
{
public:
    template<class T2>
    void Func(T2 t) { cout << t; } // 成员函数模板
};

int main()
{
    A<int> a;
    a.Func('K');     //成员函数模板 Func被实例化
    a.Func("hello"); //成员函数模板 Func再次被实例化

    return 0;
} 

 

类模版与非类型参数 :

template <class T, int size>
class CArray
{
public:
    void Print( )
    {
        for( int i = 0;i < size; ++i)
        cout << array[i] << endl;
    }
private:
    T array[size];
};

CArray<double,40> a2;
CArray<int,50> a3; //a2和a3属于不同的类

 

 

类模版与派生

 

 

 

// 基类 - 类模板
template <class T1,class T2>
class A 
{
    T1 v1; T2 v2;
};

// 派生类 - 类模板
template <class T1,class T2>
class B:public A<T2,T1> 
{
    T1 v3; T2 v4;
};

// 派生类 - 类模板
template <class T>
class C:public B<T,T> 
{
    T v5;
};

int main() 
{
    B<int,double> obj1; 
    C<int> obj2;
    return 0;
}

类模版从模版类派生

 

 

 

template <class T1,class T2>
class A 
{
    T1 v1; T2 v2;
};

template <class T>
class B:public A<int,double>  // A<int,double> 模板类
{
    T v;
};

int main() 
{
    //自动生成两个模板类 :A<int,double> 和 B<char>
    B<char> obj1;
    return 0;
}

类模版从普通类继承

 

 

 

// 基类 - 普通类
class A 
{
    int v1;
};

// 派生类 - 类模板
template <class T>
class B:public A  // 所有从B实例化得到的类 ,都以A为基类
{ 
    T v;
};

int main() 
{
    B<char> obj1;
    return 0;
}

普通类从模版类派生

 

 

 

template <class T>
class A 
{
    T v1;
};

class B:public A<int> 
{
    double v;
};

int main() 
{
    B obj1;
    return 0;
}

 

模版的完全特例化和部分特例化

如果一个模版函数是比较数值大小,当我们想进行字符串比较时,就需要对字符串类型做出一个特例,这就是模版的特例  ,可看下面例子

#include<iostream>
#include<stdlib.h>
#include<string.h>
#include<string>
#include<unistd.h>
using namespace std;
template<typename T>
class Vector {

  public:
    Vector() {cout<<"Vector()"<<endl;}
    ~Vector() {cout<<"~Vector()"<<endl;}

};

//  完全特例化
template<>
class Vector<char*> {
  
  public:
    Vector() {cout<<"Vector(char*)"<<endl;}
    ~Vector() {cout<<"~Vector(char*)"<<endl;}
};
//  对指针类型的部分特例化
  template<typename Ty>
  class Vector<Ty *> {

  public:
    Vector() {cout<<"Vector(Ty*)"<<endl;}
    ~Vector() {cout<<"~Vector(Ty*)"<<endl;}
  };


//  对返回值是指针,参数为两个的部分特例化
template<typename R, typename T1 , typename T2>
class Vector<R(*)(T1,T2)> {

  
};

int main()
{

    cout<<endl;
    return 0;
}

 

posted @ 2020-09-01 19:15  睡觉lc  阅读(245)  评论(0编辑  收藏  举报