C++模板

 

c++模板底层

  • 编译器并不是把函数模板处理成能够处理任意类的函数;编译器从函数模板通过具体类型产⽣不同的函数
  • 编译器会对函数模板进⾏两次编译:在声明的地⽅对模板代码本身进⾏编译,在 调⽤的地⽅对参数替换后的代码进⾏编译。
  • 这是因为函数模板要被实例化后才能成为真正的函数,在使⽤函数模板的源⽂件中包含函数模 板的头⽂件,如果该头⽂件中只有声明,没有定义,那编译器⽆法实例化该模板,最终导致链 接错误。

模板元编程

  • 函数名相同,参数类型不同要重新写函数。模板出现就是提高了程序的复用性,提高效率
  • 当刚上手的时候肯定是根据具体的数据类型来组织代码。随着越来越熟,用一种广泛的表达去取代具体数据类型,在c++中就叫做模板编程。

类型

  • 函数模板
  • 类模板

格式 template <template T>template <class T>

底层实现

  • 编译器将函数模板通过具体类型产生不同的函数
    • 对模板代码声明处进行编译
    • 在调用地方对替换后代码编译

模板和继承

  • 使用目的
    • 模板用于生成一组类或函数,这些类和函数的实现是一样的
    • 继承是事物之间的联系,从父类到子类是从普遍到特殊,从共性到特性
  • 多态的不同
    • 模板是编译时多态
    • 继承是运行时多态
  • 复制内容
    • 模板是对代码的复制,编译完成后,会生成对应的函数或类
    • 继承是对数据的复制,复制虚表、数据

函数模板

类型

  • 成员函数模板
  • 普通函数模板

调用方式

  • 自动推导,隐式调用
    • myswap(a, b)
    • 参数类型和模板定义的一致才可以
    • 模板必须确定出T的类型
  • 显式调用
    • myswap<int>(a, b)

普通函数和模板函数

区别

  • 普通函数调用时可以发生自动类型转换(隐式类型转换)
  • 如果使用函数模板,自动类型推导的话,则不会发生隐式转换
  • 如果使用函数模板,显式指定类型,则可以发生隐式转换

调用规则

  • 优先调用普通函数
  • 可以使用空模板参数来强制调用模板函数
  • 函数模板也可以重载
  • 如果函数模板可以产生更好的匹配,优先调用函数模板

类模板

调用方式

只有显式指定参数类型

普通类和模板类

成员函数

  • 普通类在编译时创建
  • 模板类在调用时创建

类模板对象作函数参数

  • 指定传入类型,直接显示对象的数据类型
  void print(Person<string, int>& p);
  • 参数模板化,将对象中的参数变为模板进行传递
      template <class T1, class T2>
      void print(Person<T1, T2>& p);
    
  • 整个类模板化,将整个对象类型模板化进行传递
  template <class T>
  void print(T& t);

类模板与继承

  • 当派生类继承基类的一个类模板时,子类在声明时,要指定出分类中的T类型
  template <class T>
  class father{
    T t;
  };

  // 子类在声明时,要指定出分类中的T类型
  class son : public father<int>{

  }
  • 如果还需要灵活,则子类需要变为类模板
  template <class T>
  class father{
    T t;
  };

  template <class T1, class T2>
  class son : public father <T2>{
    T1 obj;
  }
  • 类模板成员的类外实现
  // 构造函数类外实现
  template<class T1, class T2>
  Person<T1, T2>::Person(T1 name, T2 age){}

  // 成员函数类外实现
  template<class T1, class T2>
  void Person<T1, T2>::show(){}

文件要求

  • 要求模板和实现在一个文件内