zoukankan      html  css  js  c++  java
  • C++——模板---函数模板---类模板

    一、模板

    • 模板的引入:
      • 模板的精神:类型参数化,即类型也是一种参数。
      • template所代表的泛型编程是C++语言中的重要组成部分。C++是一门强类型语言,无法像动态语言(如python)那样,编写一段通用的逻辑,可以把任意类型的变量传进去。泛型编程弥补了这一点摆脱了类型的限制,提高了代码的可重用性。
      • 模板是建立通用的与数据类型无关的算法的重要手段,可实现代码重用。
    • 函数模板的定义与声明:---函数模板实参推演
      • 定义:
        • template<模板参数表>返回值类型 函数名(函数形参表){......}//函数体
        • 模板参数主要是模板类型参数,尖括号中不能为空。模板类型参数由typename(或class)+标识符构成。表示该标识符代表一种潜在的内置或用户自定义数据类型。
      • 声明:
        • 函数模板的声明与函数声明不同,函数模板的声明必须含变量名。因为两者的编译过程不一样。函数模板必须先转换成模板函数,再进行编译。模板定义本身不参与编译,而是编译器模板的用户使用模板时提供的类型参数生成代码,再进行编译。这一过程成为模板的实例化。用户提供不同的类型参数就会实例化出不同的代码。
    • 类模板的定义与声明:---类模板实例化
      • 定义:
        • template<模板参数表> class 类名
          {
          //类定义体
          };//注意分号不可少
          
          templete<模板参数表>返回类型 类名<模板参数名表>::
          成员函数名1(形参表)
          {
          ......;//成员函数定义体
          }

           模板参数表有两种:模板类型参数和非模板类型参数。




    二、函数模板---template关键字用于声明开始进行泛型编程-----typename关键字用于声明泛指类型----函数模板可以自动推导类型进行调用,也可以显示指定具体类型进行调用。

      1、普通函数模板:

      •  1 template<typename T>
         2 int compare(const T& left,const T& right)
         3 {
         4 if(left<rigth)
         5 {return -1;}
         6 if(right<left)
         7 {return 1;}
          reurn 0;
        8 } 9 10 compare<int>(1,2);//使用模板函数

      2、类的成员函数模板

    不仅普通函数可以定义为模板,类的成员函数也可以定义为模板

      • class printer
        {
        public:
        template<typename T>
        void print(const T& t)
        {
        cout<<t<<endl;
        }
        }
        
        printer p;
        p.print<const char*>("seu");//打印seu

    • 实参推断:

    为了使用方便,除了直接为函数模板指定类型参数外,还可以让编译器从传递给函数的实参推断参数类型,这一功能被称为模板实参推断。

    • 实参推断的使用:
      • 1 compare(1,2);//推断T的类型为int
        2 compare(1.0,2.0);//推断T的类型为double
        3 p.print("absdsaf");//推断T的类型为const char *
        4 
        5 int (*pf)(const int&,const int&)=compare;//推断T的类型为int;
        6 //通过把函数模板赋值给一个指定类型的函数指针,让编译器根据这个指针的类型,对模板实参进行判断

      3、函数模板的重载

    函数模板之间,函数模板与普通函数之间可以重载。编译器会根据调用时提供的函数参数,调用能够处理这一类型的最特殊的版本。在特殊性上,一般遵循如下顺序:

    • 普通函数
    • 特殊函数(限制了T的形式的,指针,引用,容器等)
    • 普通模板(对T没有任何限制的) 
    • 如何判断哪个模板函数更加特殊,原则是:如果模板B的所有实例都可以实例化模板A,而反过来不行,那么B就比A特殊。即B的范围大于A的范围。
      •  1 template<typename T>
         2 void func(T& t) { //通用模板函数
         3     cout << "In generic version template " << t << endl;
         4 }
         5 
         6 template<typename T>
         7 void func(T* t) { //指针版本
         8     cout << "In pointer version template "<< *t << endl;
         9 }
        10 
        11 void func(string* s) { //普通函数
        12     cout << "In normal function " << *s << endl;
        13 }
        14 
        15 int i = 10;
        16 func(i); //调用通用版本,其他函数或者无法实例化或者不匹配
        17 func(&i); //调用指针版本,通用版本虽然也可以用,但是编译器选择最特殊的版本
        18 string s = "abc";
        19 func(&s); //调用普通函数,通用版本和特殊版本虽然也都可以用,但是编译器选择最特化的版本
        20 func<>(&s); //调用指针版本,通过<>告诉编译器我们需要用template而不是普通函数

      4、模板函数的特化

    有时候函数模板并不能解决个别类型的问题,我们必须对此进行定制,这就是函数模板的特化。函数模板的特化必须把所有的模板参数全部指定。

    • 1 template<>
      2 void func(int i) {
      3     cout << "In special version for int "<< i << endl; 
      4 }
      5 
      6 int i = 10;
      7 func(i); //调用特化版本



    三、类模板---

    类模板只能显示指定类型参数,无法自动推断参数类型。声明的泛型类型参数可以出现在类模板的任意地方。类模板必须在头文件中实现,不能分开实现在不同的文件中。

    类模板适合以相同的逻辑处理不同数据类型的数据,因此非常适合编写数据结构相关的代码。通常用来作为容器(vector)或行为(clonable)的封装。

    对于一个类模板printer,只能显示的指定参数类型进行调用

    • printer<int> p(1);正确
      printer p(1);错误
       

     

  • 相关阅读:
    【面试题总结】第三篇
    Django 多账号登录
    Zabbix3.2 监控搭建
    2017.09.24校内训练
    2017.09.06校内训练
    tyvj P1001 第K极值
    洛谷P1020导弹拦截
    洛谷P1006传纸条
    2017.09.10校内训练
    hdu_1086 You can Solve a Geometry Problem too
  • 原文地址:https://www.cnblogs.com/southcyy/p/10263357.html
Copyright © 2011-2022 走看看