C++模板写法详解

模板
  • 概念
    • 模板就是建立通用的模具,大大提高复用性
  • 模板主要体现了cpp编程的另外一种思想泛型编程
  • cpp提供两种模板机制
    • 函数模板
    • 类模板
  • 函数模板
    • 作用
      • 建立一个通用函数,其函数返回值类型和形参类型可以不具体制定,用一个虚拟的类型来代表
    • 语法
        template<typename T>
        函数声明或定义
        //template 声明创建模版
        //typename 表面其后面的符号是一个数据类型,可以用class代替
        //T 通用数据类型,名称可替换
      
    • 使用语法
      • 自动类型推导
        • mySwap(a, b);
      • 显示指定类型
        • mySwap(a, b);
    • 举例
          #include<iostream>
          using namespace std;
          template<typename T>
          void mySwap(T& a, T& b){
              T temp = a;
              a = b;
              b = temp;
          }
          int main(){
              int a = 10;
              int b = 20;
              double c = 3.54;
              double d = 4.43;
              mySwap(a, b);
              mySwap<double>(c, d);
              cout << a << b << endl;
              cout << c << d << endl;
              return 0;
          }
      
      • 本质类型参数化
    • 注意事项
      • 自动类型推导,必须要推导出类型一致的数据类型T才可以使用
      • 模版必须要确定出T的数据类型,才可以使用
      • class可以用于函数也可以用于类typename只能用于函数
    • 普通函数与函数模板的区别
      • 普通函数调用时可以发生自动类型转换(隐式类型转换)
      • 函数模版调用时,如果利用自动类型推导,不会发生隐式类型转换
      • 如果利用显示制定类型的方式,可以发生隐式类型转换
    • 普通函数和函数模板的调用规则
      • 如果函数模板和普通函数都可以实现,优先调用普通函数
      • 可以通过空模板参数列表来强制调用函数模板
      • 函数模板也可以发生重载
      • 如果函数模板可以更好的匹配则优先调用函数模板
          myfunc<>(a, b)//空模板
      
    • 模板的局限性
      • 有些特定数据类型要用具体化方式做特殊实现
          #include<iostream>
          #include<string>
          using namespace std;
          class Person{
              public:
                  string m_name;
                  int m_age;
                  Person(string name, int age){
                      m_name = name;
                      m_age = age;
                  }
                  //函数重载是一种方法
                  // bool operator==(const Person& p){
                  //     if(this->m_age == p.m_age && this->m_name == m_name)
                  //         return true;
                  //     else
                  //         return false;
                  // }
          };
      
          template<class T>
          void myCompare(T& a, T& b){
              if(a == b){
                  cout << "same" << endl;
              }else{
                  cout << "different" << endl;
              }
          }
          //利用具体化Person的版本实现代码,具体化优先调用
          template<>void myCompare(Person& a, Person& b)
          {
              if(a.m_age == b.m_age && a.m_name == a.m_name)
                  cout << "same" << endl;
              else    
                  cout << "different" << endl;
          }
          void test(void){
              Person a("zhangsan",20);
              Person b("zhangsan", 10);
              myCompare(a, b);
          }
          int main(){
              test();
              return 0;
          }
      
  • 类模板
    • 类模板作用
      • 建立一个通用类,类中成员数据类型可以不具体制定,用一个虚拟的类型来表示
    • 语法
          template<typename T>
    • 简单举例
          #include<iostream>
          #include<string>
          using namespace std;
          template<class NameType, class AgeType>
          class Person{
              public:
                  NameType m_name;
                  AgeType m_age;
                  Person(NameType name, AgeType age){
                      this->m_age = age;
                      this->m_name = name;
                  }
                  void ShowInfor(void){
                      cout << "my name is " << this->m_name << endl;
                      cout << "my age is " << this->m_age << endl;
                  }
          };
          void test(void){
              Person<string, int>p("zhangsan", 18);//必须显式调用
              p.ShowInfor();
          }
          int main(){
              test();
              return 0;
          }
      
    • 类模板与函数模板的区别
      • 类模板没有自动推导的使用方式
      • 类模板在模板参数列表中可以有默认参数
        • template<class NameType, class AgeType = int>
    • 类模板中成员函数创建时机
      • 普通类中的成员函数一开始就可以创建
      • 类模板中的成员函数在调用时才创建
    • 类模板对象做函数参数—如何给函数传入类模板所创造的对象
      • 传入方式
        • 指定传入类型—直接显示对象的数据类型
        • 参数模板化—将对象中的参数变为模板进行传递
        • 整个类模板化—将这个对象类型模板化进行传递
      • 举例
        #include<iostream>
        #include<string>
        using namespace std;
        template<class NameType, class AgeType>
        class Person{
            public:
                NameType m_name;
                AgeType m_age;
                Person(NameType name, AgeType age){
                    this->m_age = age;
                    this->m_name = name;
                }
                void ShowInfor(void){
                    cout << "my name is " << this->m_name << endl;
                    cout << "my age is " << this->m_age << endl;
                }
        };
        //指定传入类型---最常用
        void Personshow1(Person<string, int> &p){
            p.ShowInfor();
        }
        void test1(void){
            Person<string, int>p("zhangsan", 18);
            Personshow1(p);
        }
        //参数模板化
        template<class T1, class T2>
        void Personshow2(Person<T1, T2> &p){
            p.ShowInfor();
        }
        void test2(void){
            Person<string, int>p("zhangsan", 28);
            Personshow2(p);
        }
        // 整个类型模板化
        template<class T>
        void Personshow3(T &p){
            p.ShowInfor();
        }
        void test3(void){
            Person<string, int>p("zhangsan", 38);
            Personshow3(p);
        }
        int main(){
            test1();
            test2();
            test3();
            return 0;
        }
        
    • 类模板与继承
      • 当子类继承的父类是一个类模板时,子类在声明时候,要指出父类中T的类型
      • 如果不指定,编译器无法给子类分配内存
      • 如果想灵活指定出父类中T的类型,子类也需变为类模板
      • 简单例子
            #include<iostream>
            #include<string>
            using namespace std;
            template<class T>
            class Base{
                public:
                    T name;
            };
            //第一种继承方法
            class Son1: public Base<string>{
                public:
                    void showInfor(void){
                        cout << "my name is " << this->name << endl;        
                    }
            };
            // 第二种方法进一步扩大模板
            template<class T1, class T2>
            class Son2: public Base<T1>{
                public:
                    T2 age;
                    void showInfor(void){
                        cout << "my name is " << this->name << endl; 
                        cout << "my age is " << this->age << endl;       
                    }
            };
            void test1(void){
                Son1 s;
                s.name = "zhangsan";
                s.showInfor();
            }
            void test2(void){
                Son2<string, int>s;
                s.name = "zhangsan";
                s.age = 18;
                s.showInfor();
            }
            int main(){
                test1();
                test2();
                return 0;
            }
        
    • 类模板中的成员函数的类外实现
      • 普通的类外实现
            #include<iostream>
            #include<string>
            using namespace std;
            class Person1{
                public:
                    void printInfor(void);
            };
            void Person1::printInfor(void){
                cout << "this is the test" << endl;
            }
            int main(){
                Person1 P1;
                P1.printInfor();
                return 0;
            }
        
    • 模板的类外实现
      #include<iostream>
      #include<string>
      using namespace std;
      template<class T>
      class Person1{
          public:
              T m_name;
              Person1(T name);
              void printInfor(void);
      };
      template<class T>//即使不用T也要添加这个列表
      Person1<T>::Person1(T name){
          this->m_name = name;
      }
      template<class T>//即使不用T也要添加这个列表
      void Person1<T>::printInfor(void){
          cout << "this is the test" << endl;
      }
      int main(){
          Person1<string>P1("zhangsan");
          P1.printInfor();
          return 0;
      }
      
      • 总结
        • 主要是要同步声明其为模板
        • 在定义过程的最开始要加入模板列表
    • 类模板分文件编写
      • 问题
        • 类模板中成员函数创建时机是在调用阶段,导致分文件编写时链接不到
      • 解决
        • 直接包含cpp文件
          • 一般我们include的都是.h文件,此处可以改为.cpp文件
          • 原因
            • 模板类不会一开始就生成,因此包含.h并没有什么用
        • 将声明和实现写在同一个文件中,并更改后缀名为.hpp,这是约定不是强制,用于实现类模板的实现
    • 类模板与友元
      • 掌握类模板配合友元函数的类内和类外实现
      • 全局函数类内实现—直接在类内声明友元即可—推荐—直接加入friend然后定义即可
      • 全局函数的类外实现—需要提前让编译器知道全局函数的存在
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值