zoukankan      html  css  js  c++  java
  • 泛函编程—模板函数_类模板

    函数业务逻辑一样,只是函数参数类型不同
    函数模板的本质:类型参数化——泛型编程

    语法:

    template <typename T>
    template <class T1,class T2>多个参数类型
    类型 函数名(形式参数表)
    {
      语句序列;
    }

    函数模板基础:

    template是告诉C++编译器,开始泛型编程,看到T,不要随便报错

    template <typename T>//一个模板
    void myswap(T& a, T& b)
    {
      T c;
      c = a;
      a = b;
    }
    //调用时,显式说明类型
      myswap<int>(x,y);
      myswap<char>(x,y);
    //自动类型推倒,尽量不要用
      myswap(x,y);
    
    template <typename T1, typename T2>//两个模板,定义了一定要用
    void myswap(T1& a, T2& b)
    {
    
    }

    在使用模板时,遇到修改模板里面内容,需要清除原有方案,重新编译。

    函数模板遇上函数重载:

    //函数模板不允许自动类型转化,严格的类型匹配
    //普通函数能够进行自动类型转化,在不失精度的前提下
    1、函数模板可以像普通函数一样被重载
    2、C++编译器优先考虑普通函数
    3、如果函数模板可以产生一个更好的匹配,那么选择模板(比如在使用普通函数导致精度缺失的时候)
    4、可以通过空模板实参列表的语法限定编译器只通过模板匹配

    template <typename T>//一个模板
    void myswap(T& a, T& b)
    {
      T c;
      c = a;
      a = b;
    }
    //一个普通函数
    void myswap(int& a, char& b)
    {
      int c;
      c = a;
      a = b;
    }
    int a = 10;
    char c = 'c';
    myswap(a,c) //调用普通函数
    myswap(c,a) //调用普通函数,进行隐形类型转换
    myswap(a,a) //调用模板函数,严格的类型匹配,不会进行类型转换;但是普通函数如果也有两个int形参时,优先普通函数,看下一个例子
    

    //模板函数重载
    int max(int a, int b)
    {
      return a>b?a:b;
    }
    template
    <typename T> T max(T a, T b) {   return a>b?a:b; }
    template
    <typename T> T max(T a, T b, T c) {   return max(max(a,b), c); } int a = 1; int b = 2; max(a,b); //函数模板和普通函数都满足调用时,优先普通函数 max<>(a,b);//显示使用函数模板方法,则使用<>空的类型参数化列表 max(3.0,4.0);//类型一致,可以使用模板。且使用普通函数,失真,则调用函数模板 max(3.0,4.0,5.0);//函数模板可以重载 max('a',100); //类型不一致,不能用函数模板,调用普通函数进行隐式类型转换

    函数模板机制结论:

    编译器并不是把函数模板处理成能够处理任意类的函数
    函数模板通过具体类型产生不同的函数
    编译器会对函数模板进行二次编译:
    声明的地方对模板代码本身进行编译,在调用的地方对参数替换后的代码进行编译

    类模板:
    解决问题:多个类功能一致,数据类型不同。
    类模板用于实现类所需数据的类型参数化
    类模板在表示数组、表、图等数据结构显得特别重要;
    实现 数据结构 与 算法的分离,类模板可以使 链表类型存不同数据类型数据
    类模板的定义和使用:

    template <typename T>
    class A
    {
    public:
      A(T a=0)
      {
        this->a = a;
      }
    public:
      void printA()
      {
        cout << "a: " << a << endl;
      }
    protected:
      T a;
    }
    int main() {   A<int> a1(10); //模板类是抽象的,需要进行类型具体化   a1.printA();   system("pause");   return 0; }

    类模板做函数参数:

    void useA(A<int>& b) //C++编译器要求具体的参数类
    {
      b.printA();
    }
      useA(a1);

    继承中的类模板:

    一、模板类派生普通类
    子模板类派生时,需要具体化模板类,C++编译器需要知道父类的数据类型具体是什么
    要知道父类所占内存大小,只有数据类型固定才知道如何分配内存

    class B:public A<int>
    {
    public:
      B(int a=10, int b=20):A<int>(a) //使用初始化参数列表,初始化父类对象注意父类为模板类时,使用A<int>类类型具体化
      {
      this->b = b;
      }
    protected:
    private:
      int b;
    }
      

    B b1(
    1,2);

    二、模板类派生模板类

    template <typename T>
    class C:public A<T> //基类为模板类型
    {
    public:
      C(T c, T a):A<T>(a) //基类为模板类型
      {
        this->c = c;
      }
    void printC()
    {
      cout << "c1: " << c << endl;
    }
    private:
      T c;
    }
    void main() { C<int>c1(1,2); c1.printC(); system("pause"); }

    模板类的函数重载:

    友元函数只用于重载 输入输出流 << 和 >>
    其余使用成员函数,成员函数需要在类中声明,而<<需要在ostream类中声明,但我们在C++源码中修改很麻烦,
    所以,使用友元实现。友元函数只需要在需要使用的地方的类中定义ostream为该类的友元函数就可以了。

    在模板类中写友元函数和成员函数重载的方法:
    1、所有函数声明实现都写在.h文件的内部就可以啦(简单)
    2、声明和实现分开,但都在一个.cpp内
    函数提出来的时候,参数类型、类作用域、返回值注意使用<T>
    友元函数:只用于输入输出流

    类内声明:friend ostream& operator<< <T> (ostream& out, Complex &c3); //友元函数声明有<T>
    类外实现:template<typename T>
    ostream& operator<<(ostream& out, Complex<T>& c3) //友元函数是全局函数,不需要类的作用域
    {
    
    }

    template<typename T>
    成员函数:

    类内声明: Complex operator+(Complex &c2); //正常写就可以啦
    类外定义:主要三要素
    Complex<T> Complex<T>::operator+(Complex<T>& c2)
    {
      Complex tem(a+c2.a,b+c2.b);
      return tem;
    }

    除了输入输出流使用友元函数重载,其余最好使用成员函数重载,不然处理起来很麻烦。。。

    3、.h和.hpp分开,其他类使用,要包含.hpp(不是.cpp)
    这个时候和情况2差不多,滥用友元函数容易出问题。

    模板类中的static关键字,不同的调用类型,static关键字属于不同的类,这是由模板的实现机制决定的。

    static是属于具体类的。

  • 相关阅读:
    解析·玄学 模拟退火
    NOIP2018 集训(三)
    NOIP2018 集训(二)
    NOIP2018 集训(一)
    动画制作-cartoon
    视频压缩-video cutter
    [里程碑]media pro sdk 1.0 finished
    图像去水印-image inpainting
    地平线检测horizon line detection
    二维数据缺失补全
  • 原文地址:https://www.cnblogs.com/Lunais/p/5852367.html
Copyright © 2011-2022 走看看