C++模板学习总结

来源:互联网 发布:erp软件视频介绍 编辑:程序博客网 时间:2024/06/05 15:54

模板是C++支持参数化多态的工具,使用模板可以给类 或函数声明 一种一般模式,使用户在使用模板的时候,可以自

己设定函数参数类型和返回值类型。

模板是一种对类型进行参数化的工具;

  通常有两种形式:函数模板类模板


  函数模板针对仅参数类型不同的函数;


  类模板针对仅数据成员和成员函数类型不同的类。

      使用模板就是让程序员编写与类型无关的代码。比如编写一个两个int类型的Add函数,那这个函数只能实现int类型的数相加,其他类型就不可以。要实现其他类型数字相加,就得重新编写一个Add函数。而模板的魅力就在于此,可以不考虑类型,编写一个通用的Add函数,不需要考虑 类型 。

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

--------------------------------------------------------------------------------------------------------------

一、模板的通用格式

1、函数模板的格式

template <typename  形参名,typename  形参名,...>

返回类型  函数名(参数列表)

{

 //函数体

}
其中,templatetypename是关键字,typename可以用class 代替。<>里面的是模板形参, 模板形参和函数形参很类似,模板形参一般情况不能为空(除了模板的全特化一旦声明了模板函数,就可以在该模板函数内使用模板函数形参名,即可以在该函数中使用内置类型的地方都可以使用模板形参名模板形参需要在调用该模板时提供模板实参来初始化模板形参。一旦编译器确定了模板实参就称 实例化了一个模板。

举例: Add函数的模板形式为

  template<typename T>

  T Add(T& a,T& b)

   { }

在使用Add模板函数的时候,就得给出实际的类型   例如: Add<int> (10,20);

2、类模板格式

2.1基本格式

template<class  形参名class 形参名>  

 class 类名

   { ... };

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

 template<class T> 

   class A

   {

    public: 

         T a;

          T b; 

         T Add (T c, T &d);

    };

2.2类模板对象的创建

和模板函数一样,创建模板对象的时候需要给出模板实参类型,通过实参类型,就可以实例化一个模板了。其实,可以这么理解:类模板就是一个类的抽象,类又是其类对象的一个抽象

注意

类模板形参不存在实参推演的问题。也就是说不能把整型值2推演为int 型传递给模板形参。要把类模板形参调置为int 型必须这样指定A<int> m。

2.3在类模板外部定义成员函数


template<模板形参列表>

返回类型  类名<模板形参>::函数名(函数形参列表)

{

//函数体

}

例如:template<class T1,class T2>

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

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

2.4 再次提醒!!!

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

----------------------------------------------------------------------------------------------------------

二、模板的实例化

实例化编译器用模板产生指定的类或者函数的特定类型版本,产生模板特定类型的过程称为函数模板实例化。

实例化阶段: 模板被编译两次

1、实例化之前:对模板进行语法检测

2、实例化期间:检查模板代码所有调用是否都有效

举例:

#include<iostream>using namespace std;template<typename T>T Add(T& a, T& b){return a + b;}int main(){int x = 0;int y = 1;int ret = <strong>Add<int>(x, y)</strong>; //实例化Add<int> 函数return 0;}
实参推演:从实参 确定 模板形参类型 和 值 的过程。

上面的例子分析:


类型形参转换:一般不会转换实参以匹配已有的实例化,而会产生新的实例。

转换的特例1、const转换:形参为const引用/指针 可以分别对非const的引用/指针类调用

2、数组./函数到指针的转换:如果模板形参不是引用类型,则数组实参将当做指向数组第一个元素的指针,函数实参将当做指向函数类型的指针

----------------------------------------------------------------------------------------------------------

三、模板的参数

模板形参:类型形参非类型形参


类型形参 :由关键字class、typename 后接说明符构成。

举例:

template<typename T> void Swap(T& a, T& b){T tmp = a;a = b;b = tmp;}
上面的例子中 T 就是一个类型形参,类型形参的名字有用户自己决定。模板形参表示 一个未知的类型

模板类型形参可作为类型说明符用在模板中的任何地方,与内置类型说明符或类类型说明符的使用方式完全相同,即可以用于指定返回类型,变量声明等。


    注意:1、不能为同一个模板类型形参指定两种不同的类型 (主要对于函数模板

举例:上面的 例子,如果在实例化的时候,Swap(2, 2.1); 必然会出错的。

2、模板形参名字只能 在模板形参之后到模板声明或者定义的末尾之前

         举例:

#include<iostream>using namespace std;typedef double T; template<typename T>T Add(T& a, T& b){cout << "模板参数T: " << typeid(T).name() << endl;return a + b;}T num;int main(){int x = 10;int y = 20;Add<int>(x, y);cout << "num 的类型: " << typeid(num).name() << endl;return 0;}
输出结果:

3、模板形参的名字在同一个参数列表中只能使用一次


非类型形参也就是内置类型形参

举例:template<class T, int a> class B{};其中int a就是非类型的模板形参。

     注意

1、非类型形参在模板内部是常量值,也可以说非类型形参在模板内部是常量

  2、非类型模板的形参只能是整型,指针和引用,像double,String, String **这样的类型是不允许的。但是double &,double *,对象的引用或指针是正确的。

4、模板函数的在重载应在模板函数的调用之前

 举例:

int Add(int& a, int& b, int& c)  //重载1{return a + b + c;}template<typename T>//重载2T Add(T& a, T& b,T& c){cout << "模板参数T: " << typeid(T).name() << endl;return a + b + c;}template<typename T,int C = 10>T Add(T& a, T& b){cout << "模板参数T: " << typeid(T).name() << endl;return a + b + C;}


/* 模板的特化我将在下一篇文章 着重做出学习笔记 */



0 0