zoukankan      html  css  js  c++  java
  • 【C++ 系列笔记】04 C++ 泛型编程

    泛型编程

    模板泛型的实现,泛型模板的思想。

    泛型的本质是类型的参数化。

    函数模板

    函数模板

    • 基本语法

      template<class T>
      void function(T param1, T param2){
          // ...
      }
      
      template<typename T>
      void function(T param1, T param2){
          // ...
      }
      

      <class T><typename T>没有区别。

      注意!template<class/typename T>声明仅对紧跟着的代码块有效。

    • 调用方式

      • 自动类型推导

        int a; int b;
        
        function(a, b);
        // 没问题
        
        int a; char b;
        
        function(a, b);
        // 报错
        
      • 显示指定类型

        function<int>(a, b);
        

      注意!不传参时必须显式指定类型,看下面的例子。

      template<class T>
      void function();
      
      int main(){
          function();// 此时编译器无法自动推导,必须显式指定
      }
      
    • 函数模板与普通函数的区别

      • 类型检查

        模板函数类型检查更严格,不允许隐式转换,例子:

        template<class T>
        T templateFun(T param1, T param2);
        
        int function2(int param1, int param2);
        
        int main(){
            int a; char b;
        	// 调用模板函数不允许隐式转换
            templateFun(a, c); // 报错
            
        	// 调用普通函数会发生隐式转换
            function2(a, c); // 没问题
        }
        

        不过,右值传参是允许隐式转换的,例如:

        templateFun(1, 2); // 这是合法的
        
    • 调用顺序

      重载时,优先调用普通函数

      template<class T>
      T function(T param1, T param2);
      
      int function(int param1, int param2);
      
      int main(){
          int a; int b;
          function(a, b); // 报错
      }
      

      如果想要强制调用模板函数,可以显式指定空模板参数

      function<>(a, b);
      

      如果模板函数拥有更好的参数匹配,则会调用模板函数

      template<class T>
      T function(T param1, T param2);
      
      int function(int param1, int param2);
      
      int main(){
          char a; char b;
          // 模板函数拥有更少的隐式转换,所以这里会匹配模板函数
          function(a, b);
      }
      
    • 模板函数允许重载

      template<class T>
      T function(T param1, T param2);
      
      template<class T>
      T function(T param1, T param2, T param3);
      

    模板实现机制

    • 函数模板通过具体类型产生不同的函数

    • 二次编译:

      首先检测函数模板的语法错误并编译。然后生成对应的模板函数,再次编译。

    模板具体化

    • 局限性

      函数模板具有一定的局限性,

      例如算数运算:

      对于数组,不存在 arr1 + arr2 这种语法。

      若是对象 obj1 + obj2,则需要提供相应的重载函数。

    • 解决

      函数模板的具体化:

      template<class T>
      void function(T a){
          // ... 模板实现
      }
      
      // 具体化
      template<> void function<Type>(Type& a){
          // ... 该模板函数的具体实现
      }
      

      即针对某些特定类型进行重载。

    类模板

    • 基本语法

      template<class type1, class type2>
      class Type {
         private:
          type1 __a;
          type2 __b;
         public:
          Type(type1 a, type2 b);
      }
      

      注意!与函数模板不同,实例化对象时必须显式指定数据类型。

      Type<int, char> obj(1, '2');
      
    • 默认参数

      类模板可以使用类型的默认参数。

      template<class type1, class type2 = char>
      

      当然,函数模板也可以使用默认参数,只不过没什么用。

    • 其余与函数模板基本相同

    类模板的类外实现

    代码:

    template<class type1, class type2>
    class Type {
       private:
        type1 __a;
        type2 __b;
       public:
        Type(type1 a, type2 b);
        void method(type1 a);
    };
    
    // 类外实现
    template<class type1, class type2>
    Type<type1, type2>::Type(type1 a, type2 b){
        // ...
    }
    
    template<class type1, class type2>
    void Type<type1, type2>::method(type1 a){
        // ...
    }
    

    类模板的分文件编写

    首先要了解一点,类模板的方法函数在编译阶段不会生成,他在运行时生成。

    我们调库的一般方式是这样的:

    #include"Type.h"
    int main(){
        Type obj;
        obj.method();
    }
    

    会报错,无法解析的外部命令,即在链接阶段找不到对应的函数去调用。

    因为此时还未创建具体的类模板方法函数,当然找不到。

    此时可以这样做:

    #include"Type.cpp"
    int main(){
        Type obj;
        obj.method();
    }
    

    不过,正常情况下,我们一般对类模板不做分文件编写,将声明和实现放在一个 .h文件中。

    类模板实例做函数参数

    模板实例内部的数据类型不确定,想作为参数传递,可以在参数列表里直接指定,或作为一个函数模板去定义。

    • 指定类型

      指定只允许传入此参数类型的实例:

      void function(Type<int, string> obj);
      
    • 模板函数

      允许此模板类的任何实例传入:

      template<class T1, class T2>
      void function(Type<T1, T2> obj);
      
    • 完全抽象

      其实这个方法不用说也都知道:

      template<class T>
      void function(T obj);
      

    类模板与友元

    • 类内实现

      注意!虽然是类内实现,但其作用域仍在全局。

      template<class type1, class type2>
      class Type {
          friend void function(Type<type1, type2>& obj){
              // ...
          }
         private:
          type1 __a;
          type2 __b;
      };
      
    • 类外实现

      首先看错误实现:

      template<class type1, class type2>
      class Type {
          friend void function(Type<type1, type2>& obj);
         private:
          type1 __a;
          type2 __b;
      };
      
      template<class type1, class type2>
      void function(Type<type1, type2>& obj){
              // ...
      }
      

      此时若调用该函数,则报错无法解析的命令,即没有找到该函数的实现。

      由于类内声明是一个普通函数,而类外实现是一个函数模板,而当参数列表相同时,编译器会优先调用普通函数,从而导致了找不到函数实现,链接出错。

      两种方法:

      • 声明模板函数

        此时将类内的友元声明声明为一个模板函数即可。

        template<class type1, class type2>
        class Type {
            template<class type1, class type2>
            friend void function(Type<type1, type2>& obj);
           private:
            type1 __a;
            type2 __b;
        };
        
        template<class type1, class type2>
        void function(Type<type1, type2>& obj){
                // ...
        }
        
      • 函数模板具体化

        或者先声明该模板函数,然后类内声明友元,并进行参数的具体化。

        // 声明
        template<class type1, class type2> class Type<type1, type2>
        template<class type1, class type2> void function(Type<type1, type2>& obj);
        
        template<class type1, class type2>
        class Type {
            // 参数具体化声明
            friend void function<>(Type<type1, type2>& obj);
           private:
            type1 __a;
            type2 __b;
        };
        // 类外具体化实现
        template<class type1, class type2>
        void function(Type<type1, type2>& obj){
                // ...
        }
        

    模板中的继承

    错误示例:

    不允许继承抽象的类

    template <class T>
    class Base {};
    
    // 继承
    class Type : public Base {};
    

    要继承,可以抽象,也可以具体。

    • 具体制定要继承的模板类

      template <class T>
      class Base {};
      
      // 继承
      class Type : public Base<int> {};
      
    • 抽象指定

      template <class T>
      class Base {};
      
      // 继承
      template <class T>
      class Type : public Base<T> {};
      
  • 相关阅读:
    密码学-网站的安全登录认证设计
    密码学-软件加密技术和注册机制
    密码学-数字证书原理
    Linux-ssh证书登录(实例详解)
    unity, multi collider
    unity, 相机空间 与 相机gameObject的局部空间
    unity, WaterProDaytime注意事项。
    unity, 欧拉角(euler angle)
    unity, mono断点
    unity5, import fbx注意事项
  • 原文地址:https://www.cnblogs.com/gaolihai/p/13149744.html
Copyright © 2011-2022 走看看