C++模板详细整理

C++模板

1 模板的概念

模板 字面意思和模型相似,造一个东西,总会有一个模型为基础。如果以后有什么改动,也要在模型的基础上改在。 这么想,大家都知道了 c++里模板也一样也是模型,那这个模型有什么用呢 。

例如,我们希望编写一个函数来比较俩个值,并指出第一个值,是小于?还是大于?还是等于,第二个值。在以前,我们可能想要定义多个函数,每个函数比较一种特定的类型的值。我们会写个重载函数:

int compare(const string &v1,const string &v2)
{
    if(v1<v2) 
        return 1;
    if(v2<v1)
        return -1;
    return 0;
}


int compare(const double&v1,const double &v2)
{
    if(v1<v2) 
        return 1;
    if(v2<v1)
        return -1;
    return 0;
}

这两个函数几乎相同,唯一的差异就是参数类型不同,函数体则完全相同。

如果对每种希望比较的类型都不得不重复定义完全一样的函数体,是非常容易出错的 。甚至让人崩溃(在我以前不知道模板的时候)
但是模板出现后,就大大不一样了,很方便,用法也很简单。接下来学习简单的函数模板。

1.1 函数模板
我们可以定义一个通用的函数模板,而不是为每个类型定义一个新函数。一个函数模板就是一个模型一个公式,可以生成特定类型的函数版本。compare模板可以像这样定义。

template <typename T>
int compare (const T &v1 , const T &v2)
{
    if(v1<v2)return 1;
    if(v2<v1)return -1;
    return 0;
}

1.1.1 函数模板的格式:

 template <class 形参名,class 形参名,......> 返回类型 函数名(参数列表)
 {
   函数体
 }

其中template和class,没错,他两是一样的。在这里typename 和class没区别

以关键字 template开始,后面跟一个模板参数列表。用< >包围起来。

1.1.2 实例化函数模板
当我们调用一个函数模板时候,编译器 用 函数的实参 来为我们推断 模板的实参类型。比如,我们调用上面的compar时候,编译器就知道自己的模板参数T是什么类型了。

cout << compare(1,0)<<endl;  //T为 int类型

实参类型是 int 编译器会推断出模板实参 为 int ,并将它绑定到模板参数 T 上。
接着,编译器根据 他自己推断出的 模板参数 来为我们 实例化一个特定的函数,(就专门为你制定的哦)。

当编译器实例化一个模板时,她会使用实际的模板参数 代替 对应的模板参数 来创建出模板的一个新实例。
例如 :

//实例化出 int comnpare (const int &, const int &)
cout <<compare (1 , 0) << endl; //T 为 int

//实例化出 int compare(const vector<int>&,const //vector<int>& 
 vector<int> vec{1,2,3},vwc2{4,5,6};
 cout <<compare(vec1,vec2)<<endl; // T为 vector<int>

编译器会实例化两个不同的 compare。

1.2 类模板
类模板 是用来生成类的蓝图的,与函数模板不同的地方是,编译器不能为类模板推断模板参数类型。 除非有额外的信息,接下来会说到。

定义类模板

1.2.1、类模板的格式为:

    template<class  形参名,class 形参名,…>   class 类名

    { ... };
类似函数模板,类模板以关键字 template 开始,后面跟模板参数列表。在类模板及其中的成员,我们将模板参数当做替身,代替使用模板的时候,用户需要提供类型 或 值。

以下是一些例子 大家参考一下。

// ClassTemplate.h

template<typename T1,typename T2>

class myClass{

private:

    T1 I;

    T2 J;

public:

    myClass(T1 a, T2 b);//Constructor

    void show();

};

//这是构造函数

//注意这些格式

template <typename T1,typename T2>

myClass<T1,T2>::myClass(T1 a,T2 b):I(a),J(b){}


//这是void show();

template <typename T1,typename T2>

void myClass<T1,T2>::show()

{

    cout<<"I="<<I<<", J="<<J<<endl;

}
// Test.cpp

#include<iostream>

#include"ClassTemplate.h"

using std::cout;

using std::endl;


void main()

{

    myClass<int,int> class1(3,5);

    class1.show();


    myClass<int,char> class2(3,"a");

    class2.show();


    myClass<double,int> class3(2.9,10);

    class3.show();

    system("PAUSE");

}

1.2.1 类模板和函数模板,都是以template开始,后接模板形参列表组成。模板形参不能为空,一但声明了类模板就可以用类模板的形参名,声明类中的成员变量和成员函数。即可以在类中使用内置类型的地方都可以使用模板形参名来声明。比如

  template<class T>
  class A {
  public:
   T a; T b;
   T hy(T c, T &d);
   };

//在类A中声明了两个类型为T的成员变量a和b,还声明了一个返回类型为T带两个参数类型为T的函数hy。

1.2.3
类模板对象的创建:比如一个模板类A,则使用类模板创建对象的方法为A< i n t > m;在类A后面跟上一个<>尖括号并在里面填上相应的类型,这样的话类A中凡是用到模板形参的地方都会被int 所代替。当类模板有两个模板形参时创建对象的方法为A < int, double > m;类型之间用逗号隔开。

1.2.4
对于类模板,模板形参的类型必须在类名后的尖括号中明确指定。比如A< 2 > m;用这种方法把模板形参设置为int是错误的(编译错误:error C2079: ‘a’ uses undefined class ‘A< int >’),类模板形参不存在实参推演的问题。也就是说不能把整型值2推演为int 型传递给模板形参。要把类模板形参调置为int 型必须这样指定A< int > m。

1.2.5
在类模板外部定义成员函数的方法为:

    template<模板形参列表> 函数返回类型 类名<模板形参名>::函数名(参数列表){函数体},

比如有两个模板形参T1,T2的类A中含有一个void h()函数,则定义该函数的语法为:

  template<class T1,class T2> void A<T1,T2>::h(){}

注意:当在类外面定义类的成员时template后面的模板形参应与要定义的类的模板形参一致。

1.2.6
再次提醒注意:模板的声明或定义只能在全局,命名空间或类范围内进行。即不能在局部范围,函数内进行,比如不能在main函数中声明或定义一个模板。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章