C++模板

C++模板

  • 1.函数模板(泛型)
    • 语法:template<typename T>或template<class T>(T只是个符号,可以换成其它的字符)
      template<class T,class N,…>
    //假设要实现两数的交换,如果用普通的方法实现,不同数据类型需要定义不同的函数
    void swapInt(int a,int b){
        int temp;
        temp = a;
        a = b;
        b = temp;
        
    }
    void swapDouble(double a,double b){
        double temp;
        temp = a;
        a = b;
        b = temp;
    }
    
    //使用模板,将函数的形参定义为通用数据类型,这样用一个函数即可实现多种数据类型的交换。
    //函数模板
    template<typename T>
    void Swap(T &a,T&b){
        T temp = a;
        a = b;
        b = temp;		
    }
    int main(){
        int a = 123;
        int b = 21;
        //函数模板的调用
        //1.自动类型推导
        Swap(a,b);
        cout << a << "," << b << endl;
        //2.显示指定类型
        Swap<int>(a,b);
        cout << a << "," << b << endl;
        return 0;
    }
    
    • 普通函数与函数模板的区别
      • 普通函数调用可以发生隐式类型转换
      • 函数模板用自动类型推导,不可以发生隐式类型转换
      • 函数模板用显示类型,可以发生隐式类型转换
    #include <iostream>
    using namespace std;
    #include <string>
    
    int f(int a,int b){
        return a + b;
    }
    
    template<class T>
    T ff(T a,T b){
        return a + b;
    }
    int main(){
        int a = 12;
        int b = 23;
        cout << f(a,b) << endl;//正常调用
        char c = 'c';
        cout << f(a,c) << endl;//发生隐式类型转换,编译器自动将c转为ASCII码编号
    
        //函数模板
        cout << ff(a,b) << endl;//正常自动类型推导调用
        //ff(a,c); //错误,自动类型推导无法发生隐式转换
        cout << ff<int>(a,c) << endl;//正确,指定类型可以发生隐式类型转换
    }
    
    • 普通函数和函数模板的调用规则
      • 二者皆可调用时,优先调用普通函数
      • 可以通过空模板参数列表来强制调用函数模板
      • 函数模板也可以发生重载
      • 如果函数模板可以产生更好的匹配,优先调用函数模板
    #include <iostream>
    using namespace std;
    #include <string>
    
    int f(int a,int b){
        cout << "调用普通函数" << endl;
        return a + b;
    }
    
    template<class T>
    T f(T a,T b){
        cout << "调用函数模板" << endl;
        return a * b;
    }
    
    template<class T>
    T f(T a){
        cout << "调用函数模板" << endl;
        return a;
    }
    int main(){
        int a = 12;
        int b = 23;
        //二者皆可调用时,优先调用普通函数
        cout << f(a,b) << endl;//调用普通函数
    
        //通过空模板参数列表来强制调用函数模板
        cout << f<>(a,b) << endl;//调用函数模板
    
        //函数模板也可以发生重载
        cout << f(a) <<endl;
        
        char x = 'x';
        char y = 'y';
        //函数模板可以产生更好的匹配,优先调用函数模板
        cout << f(x,y) << endl;
    }
    
    • 模板的局限性
      并非所有的泛型都满足函数体内部的操作
    #include <iostream>
    using namespace std;
    #include <string>
    
    template <class T>
    T f(T a,T b){
        return a + b;
    }
    
    class Person{
    public:
        Person(int x){
            this -> x = x;
        }
        int x;
    };
    
    int main(){
        int a = 123;
        int b = 234;
        cout << f(a,b) << endl;//正常操作
    
        Person p1(12);
        Person p2(23);
        //cout << f(p1,p2) <<endl; 错误操作,对象无法直接相加
    }
    
    • 解决办法
      • 1.运算符重载
      • 2.模板重载
    #include <iostream>
    using namespace std;
    #include <string>
    
    template <class T>
    T f(T a,T b){
        return a + b;
    }
    class Person{
    public:
        Person(int x){
            this -> x = x;
        }
        int x;
    };
    //具体化Person,具体化优先调用
    template<>Person f(Person a,Person b){
        Person c(0);
        c.x = a.x + b.x;
        return c;
    }
    int main(){
        int a = 123;
        int b = 234;
        cout << f(a,b) << endl;//正常操作
        Person p1(12);
        Person p2(23);
        cout << f(p1,p2).x <<endl; 
    }
    
  • 2.类模板
    • 语法:与函数模板一致,在类前加template <class T>
    #include <iostream>
    using namespace std;
    #include <string>
    
    template <typename T,typename N>
    class Person{
    public:
        Person(T age,N name){
            this -> age = age;
            this -> name = name;
        }
    
        T age;
        N name;
    };
    int main(){
        Person<int,string> p1(123,"A");
        //Person p1(123,"A");错误,类模板无法自动类型推导
        cout << p1.age <<p1.name <<endl;
    }
    
    • 类模板与函数模板的区别
      • 类模板没有自动类型推导
      • 类模板的模板参数列表中支持默认参数
        template <class T,class N = int>
        
    • 类作为函数参数
      • 指定传入类型
      #include <iostream>
      using namespace std;
      #include <string>
      
      template <typename T,typename N>
      class Person{
      public:
          Person(T age,N name){
              this -> age = age;
              this -> name = name;
          }
      
          T age;
          N name;
      };
      void f(Person<int,string> p1){
          cout << p1.age << "," << p1.name <<endl;
      }
      int main(){
          Person<int,string> p1(123,"A");
          f(p1);
          return 0;
      }
      
      • 参数模板化
      void f(Person<int,string> p1){
          cout << p1.age << "," << p1.name <<endl;
      }
      
      • 类模板化
      template<class T>
      void f(T p1){
          cout << p1.age << "," << p1.name <<endl;
      }
      
    • 类模板与继承
      • 当父类是一个类模板时,子类在声明时需指定父类参数的类型
      • 不指定,编译器无法给子类分配内存
      • 要想灵活指定父类T的类型,子类也需转为类模板
    #include <iostream>
    using namespace std;
    #include <string>
    
    template <class T,class N>
    class Person{
    public:
        Person(){cout << "aaaaa" << endl;};
        Person(T age,N name){
            this -> age = age;
            this -> name = name;
            cout << "aacccca" << endl;
        }
        T age = 1;
        N name = "a";
    };
    //指定父类参数类型
    class Person1:public Person<int,string>{
    public:
        Person1(){};
        Person1(int a,string b):Person(a,b){
        }
        void f(){
            cout << this -> age << "," << this -> name << endl;
        }
    };
    
    int main(){
        Person1 p1(12,"a");
        p1.f();
        return 0;
    }
    
    //子类也转为模板
    template <class T,class N>
    class Person1:public Person<T,N>{
    public:
        Person1(){};
        Person1(T a,N b):Person<T,N>(a,b){
        }
        void f(){
            cout << this -> age << "," << this -> name << endl;
        }
    };
    
    int main(){
        Person1<int,string> p1(12,"a");
        p1.f();
        return 0;
    }
    
    • 类模板,函数类外实现
    #include <iostream>
    using namespace std;
    #include <string>
    
    template <class T,class N>
    class Person{
    public:
        Person(){cout << "aaaaa" << endl;};
        Person(T age,N name);
        void f();
        T age = 1;
        N name = "a";
    };
    //类外构造函数
    template <class T,class N>
    Person<T,N>::Person(T age,N name){
            this -> age = age;
            this -> name = name;
            cout << "aacccca" << endl;
        }
    //类外成员函数
    template <class T,class N>
    void Person<T,N>::f()
    {
        cout << this -> age << "," << this -> name << endl;
    }
    
    int main(){
        Person<int,string> p(12,"a");
        p.f();
        return 0;
    }
    
    • 类模板与友元
      • 全局函数类内实现
      #include <iostream>
      using namespace std;
      #include <string>
      
      template <class T,class N>
      class Person{
          //f通过friend修饰,f并非成员函数,而是全局函数
          friend void f(Person<T,N> p){
              cout << p.age << "," << p.name << endl;
      public:
          Person(T age,N name){
              this -> age = age;
              this -> name = name;
          }
          T age;
          N name;
          }
      };
      int main(){
          Person<int ,string> p(12,"a");
          f(p);
      }
      
      • 全局函数类外实现
      #include <iostream>
      using namespace std;
      #include <string>
      
      //全局变量f用到了Person类,因此要提前声明
      template <class T,class N>
      class Person;
      //提前让编译器知道全局变量f
      template <class T,class N>
      void f(Person<T,N> p){
          cout << p.age << "," << p.name << endl;
      }
      
      template <class T,class N>
      class Person{
          //添加空模板参数列表
          friend void f<>(Person<T,N> p);
      public:
          Person(T age,N name){
              this -> age = age;
              this -> name = name;
          }
          T age;
          N name;
      };
      
      int main(){
          Person<int ,string> p(12,"a");
          f(p);
      }
      
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值