【C++标准模板库笔记1】C++的模板技术

来源:互联网 发布:西安传智java培训 编辑:程序博客网 时间:2024/05/16 18:22
/************************************************************************************************************************文件说明:        C++的模板技术开发环境:        Win10+VS2013+STL时间地点:        陕西师范大学 文津楼 2017.7.26作    者:        九 月*************************************************************************************************************************/

(一)C++模板技术的简介

        1)C++模板是一种十分重要的技术,STL标准模板库的一般算法和容器就是通过模板编程实现的,并以函数模板和类模板提供出来。

        2)顾名思义,模板的作用就在于定制函数和类。只要将数据类型传递给函数模板和类模板,就可以生成特定数据类型下的函数和类,实现了数据类型不同、但是程序逻辑完全相同的代码重用,减轻了编程的工作量,并可使大量常用的功能代码完整而简洁的纳入到标准库中,极大的改善了C++的变成环境。

        3)模板纯粹是为了将预处理宏推广到C++而来,不同于宏使用一套"指令开头用#,指令结尾不适用分号,标识符定义不适用类型"的备受争议的语法。

        4)模板的定义可以跟函数和类的定义融合在一起,完全是在它们的基础上添加一些新的语法,因此又称为函数模板和类模板,表明模板的语法仿照了熟悉的函数和类的语法,只是数据类型需要用关键字templates声明为泛型。

(二)函数模板

(1)函数模板的概念

      假设要编写一个函数对两个参数求和。实际编程中,我们可能希望定义几个这样的函数,每一个可以对一种给定类型的值求和,那么可能自然会想到函数的重载。例如:

int add(int a, int b){return a + b;}double add(double a, double b){return a + b;}char add(char a, char b){return a + b;}
       这些函数几乎相同,每个函数的函数体是相同的,功能也是相同的,它们之间唯一的不同在于形参的类型和函数返回值的类型。

       事实上,在具体编写上述代码时,我们必须手工的书写所有的代码,所以会使用复制、粘贴、修改的编辑功能得到另一种类型的求和函数。如果每种类型都需要重复函数的函数体,不仅麻烦,而且容易出错。更重要的是,需要事先知道可能会支持的所有类型的组合情况。如果希望将函数用于未知类型,这种方法就是有问题的。

       C++有模板(template)机制,可以使用函数模板解决上述存在的问题。函数模板(function template)是一个独立于类型的函数,可作为一种模式,产生函数的特定类型版本。

       使用函数模板可以设计通用型的函数,这些函数与类型无关,并且只在需要时自动实例化,从而形成"批量型"的编程方式。

(2)函数模板的定义和使用

   (1)函数模板的定义

        函数模板定义的语法形式为:

template<模板形参表>返回值类型 函数名(形式参数列表){函数体}
        可以约定,第1行称为模板定义,其后称为模板函数,与函数定义语法类似。

        模板定义以关键字template开始,后接模板形参表。模板形参表(template parameter list)是用一对尖括号<>括起来的一个或多个模板形参的列表,不允许为空,形参之间以逗号分隔,其形式有两种:

第一种形式如下所示:      typename 类型参数名1,typename 类型参数名2............第二种形式如下所示:      class 类型参数名1,class 类型参数名2................... 
        在函数模板形参表中,typename和class具有相同含义,可以互换使用,或者两个关键字都可以在同一模板形参表中使用。

        不过由于C++中class关键字往往容易与类联系在一起,所以使用关键字typename比使用class更直观,typename可以更加直观的反映出后面的名字是一个类型名。

        模板定义的后面是函数定义,在函数定义中,可以使用模板形参表中的类型参数。例如:

template<typename T> add(T a, T b){    return a + b;}
       函数模板定义语法的含义是一个通用型函数,这个函数类型和形参类型没有具体的指定,而是一个类型记号表示,类型记号由编译器根据所用的函数而确定,这种通用型函数成为函数模板。
       使用函数模板时,编译器会推断那个(或那些)模板实参绑定到模板形参上,一旦编译器确定了实际的模板实参,将实例化函数模板。即编译器将确定用什么类型代替每个类型形参,以及用什么值代替每个非类型形参,推导出实际的模板实参后,编译器使用类型实参代替相应的模板形参产生并编译该版本的函数。这里,编译器承担了我们使用的每种类型编写的重复工作,我们不用在机械的复制、黏贴、修改等手工书写了。

   (2)函数模板的使用

      可以像普通函数那样使用模板函数调用。

#include<iostream>using namespace std;template<typename T>T add(T a, T b){return a + b;}int main(){std::cout << "int_add    = "    << add(10,20)<< std::endl;std::cout << "double_add = "    << add(10.2, 20.5) << std::endl;std::cout << "char_add   = "    << add(10, 20) << std::endl;std::system("pause");return 0;}

(三)类模板

(1)类模板的简介

     类似于函数模板的做法,类模板对数据成员的数据类型和成员函数的参数类型进行泛化。如下是类模板的一个基本定义形式,关键字template说明类型T1~Tn是模本类型,成员函数可在类模板的声明中定义。

template<class T1,class T2,.....,class Tn> class 类名{//成员声明或定义;};template<class T1, class T2, ....., class Tn> 返回值 类名<T1,T2, ....., Tn>::成员函数1{//函数定义}template<class T1, class T2, ....., class Tn> 返回值 类名<T1, T2, ....., Tn>::成员函数2{//函数定义}
注意:

       不同于非模板代码的组织方式,函数模板和类模板的声明和定义代码,一般都编写在.h头文件中,以免由于为具现而提示编译链接错误。

       下面给出一个类模板表示平面上点的示例:

template<class T>                                   //【0】类模板定义class Point                                          //【1】Point不是类名是模板名{public:Point::x(0), y(0) {}                             //【2】默认构造函数Point(const T a, const T b) :(x)(a), y(b) {}    //【3】带参数的构造函数void Set(const T a, const T b);void Display();private:T x;T y;};