• c++模板


    通俗的讲,模板的作用:一段代码可以适用多个场景。

    函数模板:模板的关键词为template

    函数模板格式:

    template<模板参数列表>

    类型名  函数名(参数列表)

    {   内容    }

    模板参数列表有两种:(两者都可以使用)

    1. tpyename
    2. class
    1. template<class T>
    2. template<typename T>
    T 为数据类型,可以为int ,char 等数据类型

    函数模板两种使用方式:(一般使用还是给出数据类型更为直观)

    1.自动类型推导

    2.必须给出数据类型 

    1. template<class T>
    2. void show(T a,T b)
    3. {
    4. cout << a << endl;
    5. cout << b << endl;
    6. }
    7. int main()
    8. {
    9. //自动类型推导
    10. int a = 10;
    11. int b = 20;
    12. show(a,b);
    13. //给出类型也可以使用
    14. show<int>(a, b);

     不可自动类型推导的情况:

    1. 当函数没有参数时,不能使用自动类型推导
    2. 当函数模板参数类型和模板的参数类型不存在对应关系时,不能使用自动类型推导
    3. 与函数模板返回值相关的模板参数不能进行自动推导

    4. 自动推导必须从左到右推导,不能间隔

     1.当函数模板没有参数时:

     2.当函数模板参数类型和模板的参数类型不存在对应关系时

     

     3.与函数模板返回值相关的模板参数不能进行自动推导

    4. 自动推导必须从左到右推导,不能间隔

     

     函数模板和函数的区别:  

    1.普通函数调用时可以发生自动类型转换(隐式类型转换)

    2.函数模板调用时,利用自动类型推导,不会发生隐式类型转换

    3.利用显示指定类型的方式,可以发生隐式类型转换

    4.模板本身不会生成任何目标代码,只有模板生成的实例会生成目标代码

    5.函数指针也只能指向模板的实例,不能指向模板本身

    6.函数模板应该和函数体一同放到头文件中

     1.普通函数调用时可以发生自动类型转换(隐式类型转换)

    1. //普通函数
    2. void show(int a,int b)
    3. {
    4. cout << a + b << endl;
    5. }
    6. int main()
    7. {
    8. int a = 10;
    9. char c = 'a';//a=97
    10. //发生隐式转换 把char类型转换为int 类型
    11. show(a, c);
    12. return 0;
    13. }

     2.函数模板调用时,利用自动类型推导,不会发生隐式类型转换

    1. //模板函数
    2. template<class T>
    3. void show(T a,T b)
    4. {
    5. cout << a + b << endl;
    6. }
    7. int main()
    8. {
    9. int a = 10;
    10. char c = 'a';
    11. //自动类型转换
    12. //报错 类型不匹配,无法发生隐式类型转换
    13. show(a, c);
    14. return 0;
    15. }

     3.利用显示指定类型的方式,可以发生隐式类型转换

    1. template<class T>
    2. void show(T a,T b)
    3. {
    4. cout << a + b << endl;
    5. }
    6. int main()
    7. {
    8. int a = 10;
    9. char c = 'a';
    10. //显示指定类型
    11. //类型不匹配,但可以发生隐式类型转换
    12. show<int>(a, c);
    13. return 0;
    14. }

     普通函数和函数模板调用规则:

    1.函数模板和普通函数都可以实现,优先调用普通函数

    2.可以通过空模板参数列表来强制调用函数模板

    3.函数模板可以发生重载

    4.函数模板可以产生更好的匹配,优先使用函数模板 

     1.函数模板和普通函数都可以实现,优先调用普通函数

    1. template<class T>
    2. void show(T a,T b)
    3. {
    4. cout << a + b << endl;
    5. cout << "函数模板的调用" << endl;
    6. }
    7. void show(int a, int b)
    8. {
    9. cout << a + b << endl;
    10. cout << "普通函数的调用" << endl;
    11. }
    12. int main()
    13. {
    14. int a = 10;
    15. int b = 20;
    16. show(a, b);
    17. return 0;
    18. }

    2.可以通过空模板参数列表来强制调用函数模板

    1. template<class T>
    2. void show(T a,T b)
    3. {
    4. cout << a + b << endl;
    5. cout << "函数模板的调用" << endl;
    6. }
    7. //当普通函数有声明未实现时
    8. void show(int a, int b);
    9. int main()
    10. {
    11. int a = 10;
    12. int b = 20;
    13. //通过空模板列表强制调用函数模板
    14. show<>(a, b);
    15. return 0;
    16. }

     

     3.函数模板可以发生重载

    1. template<class T>
    2. void show(T a,T b)
    3. {
    4. cout << a + b << endl;
    5. }
    6. //函数模板重载
    7. template<class T>
    8. void show(T a, T b, T c)
    9. {
    10. cout << a + b + c << endl;
    11. }
    12. int main()
    13. {
    14. int a = 10;
    15. int b = 20;
    16. int c = 30;
    17. show(a, b);
    18. //重载使用
    19. show(a, b, c);
    20. return 0;
    21. }

     4.函数模板可以产生更好的匹配,优先使用函数模板 

    1. template<class T>
    2. void show(T a,T b)
    3. {
    4. cout << a << endl;
    5. cout << b << endl;
    6. cout << "函数模板的调用" << endl;
    7. }
    8. //普通函数
    9. void show(int a,int b)
    10. {
    11. cout << a << endl;
    12. cout << b << endl;
    13. cout << "普通函数的调用" << endl;
    14. }
    15. int main()
    16. {
    17. char a = 10;
    18. char b = 20;
    19. show(a, b);
    20. return 0;
    21. }

    模板函数的局限性:

    1.当数据类型为自定义数据类型时可能不适用

    2.当数据为一个数组时可能也不适用

    类模板 :

    类模板格式:

    template<class/typename  T,...>

    class  类名

    {

    }

    类模板和函数模板的区别:

    1.类模板没有自动类型推导

    2.类模板可以有默认数据类型 

    1. template<class T>
    2. class person
    3. {
    4. perosn();
    5. T a;
    6. };
    7. int main()
    8. {
    9. //报错 不能自动类型推导
    10. person p;
    11. //必须给出数据类型
    12. person<int>p1;
    13. return 0;
    14. }
    1. template<class T=int>//可以有默认参数
    2. class person
    3. {
    4. perosn();
    5. T a;
    6. };
    7. int main()
    8. {
    9. //有默认参数可以不给出数据类型
    10. person<>p1;
    11. return 0;
    12. }

    类模板中成员函数创建时机:

    1.普通类的成员函数在调用前就已经创建

    2.类模板的成员函数在调用前才创建 

     

     类模板做函数参数:

    1. 指定传入类型
    2. 参数模板化
    3. 类模板化
    1. template<class T1,class T2>
    2. class person
    3. {
    4. public:
    5. person(T1 a, T2 b)
    6. {
    7. this->age = a;
    8. this->name = b;
    9. }
    10. T1 age;
    11. T2 name;
    12. };
    13. //1.传入指定参数
    14. void show(person<int,string>&p)
    15. {
    16. cout << p.age << endl;
    17. cout << p.name << endl;
    18. }
    19. //2.参数模板化
    20. template<class T1,class T2>
    21. void show1(person<T1,T2>&p)
    22. {
    23. cout << p.age << endl;
    24. cout << p.name << endl;
    25. }
    26. //3.类模板化
    27. template<class T>
    28. void show2(T &p)
    29. {
    30. cout << p.age << endl;
    31. cout << p.name << endl;
    32. }
    33. int main()
    34. {
    35. person<int, string>p1(10,"wang");
    36. show(p1);
    37. show1(p1);
    38. show2(p1);
    39. return 0;
    40. }

    类模板与继承:

     1.当父类是一个类模板时,子类需要给出数据类型(不然编译器无法分配内存)

    1. template<class T1,class T2>
    2. class person
    3. {
    4. public:
    5. person(T1 a, T2 b)
    6. {
    7. this->age = a;
    8. this->name = b;
    9. }
    10. T1 age;
    11. T2 name;
    12. };
    13. //继承时需要指定数据类型
    14. class son :public person<int,string>
    15. {
    16. };

    2.想要更加灵活的使用,可以使子类也成为类模板

    1. template<class T1,class T2>
    2. class person
    3. {
    4. public:
    5. person(T1 a, T2 b)
    6. {
    7. this->age = a;
    8. this->name = b;
    9. }
    10. T1 age;
    11. T2 name;
    12. };
    13. //子类也为类模板
    14. template <class T1,class T2,class T3>
    15. class son :public person<T1,T2>
    16. {
    17. public:
    18. T1 age;
    19. T2 name;
    20. };

    模板类分文件编写:

     1.成员函数的类外实现

    1. //类模板
    2. template<class T1,class T2>
    3. class person
    4. {
    5. public:
    6. person(T1 a, T2 b)
    7. {
    8. this->age = a;
    9. this->name = b;
    10. }
    11. //成员函数
    12. void show();
    13. T1 age;
    14. T2 name;
    15. };
    16. //成员函数类外实现 需要添加类模板格式
    17. template <class T1,class T2>
    18. void person::show()
    19. {
    20. cout << age << end;
    21. cout << name << endl;
    22. }

    2.分文件编写统一创建一个 .hpp文件

    第一种:.h定义 .cpp实现

    第二种:定义和实现放到一个 .hpp中(名称并非固定)

    .hpp代码:

    1. #include<iostream>
    2. using namespace std;
    3. template<class T>
    4. class person
    5. {
    6. public:
    7. person(T a1);
    8. void show();
    9. T a;
    10. };
    11. template<class T>
    12. person::person(T a1)
    13. {
    14. this->a = a1;
    15. }
    16. template<class T>
    17. void person::show()
    18. {
    19. cout << a << endl;
    20. }

    在主函数中创建一个person对象 

    1. #include<iostream>
    2. #include<string>
    3. #include"源1.hpp"
    4. using namespace std;
    5. int main()
    6. {
    7. //创建一个person对象
    8. person<int> p(10);
    9. return 0;
    10. }

    类模板与友元函数:

    一般都会选择类内声明和实现

     1.友元函数在类内实现

    1. template<class T>
    2. class person
    3. {
    4. //1.全局函数类内实现
    5. friend void set_age(person<T>&p, T a)
    6. {
    7. p.age = a;
    8. }
    9. public:
    10. person(T a)
    11. {
    12. this->age = a;
    13. }
    14. T get_age()
    15. {
    16. cout << age << endl;
    17. return age;
    18. }
    19. private:
    20. T age;
    21. };
    22. int main()
    23. {
    24. person<int>p(20);
    25. set_age(p, 30);
    26. p.get_age();
    27. return 0;
    28. }

    2.友元函数类外实现

    1. //需要让友元函数提前知道person
    2. template <class T>
    3. class person;
    4. //需要让编译器提前知道该友元函数
    5. template<class T>
    6. void set_age(person<T>&p, T a)
    7. {
    8. p.age = a;
    9. }
    10. template<class T>
    11. class person
    12. {
    13. //函数类内声明
    14. //需要添加空模板参数列表<>
    15. friend void set_age<>(person<T>&p, T a);
    16. public:
    17. person(T a)
    18. {
    19. this->age = a;
    20. }
    21. T get_age()
    22. {
    23. cout << age << endl;
    24. return age;
    25. }
    26. private:
    27. T age;
    28. };
    29. int main()
    30. {
    31. person<int>p(20);
    32. set_age(p, 30);
    33. p.get_age();
    34. return 0;
    35. }

    类模板中静态成员函数的处理:

    类模板中可以定义静态成员,从该类模板实例化得到的所有类都包含同样的静态成员。

    1. template <class T1>
    2. class person
    3. {
    4. public:
    5. T1 a;
    6. static int b;
    7. };
    8. template<> int person<int>::b = 10;
    9. int main()
    10. {
    11. person<int>p1;
    12. person<int>p2;
    13. cout << p1.b << endl;
    14. cout << p2.b << endl;
    15. return 0;
    16. }

     

  • 相关阅读:
    Redis教程
    精心准备200题Java相关面试,友情分享
    MybatisPlus处理业务数据新思路
    RT-Thread实战笔记-小白一看就会的平衡车教程(附源码)
    【API封装接口的应用】大数据值得深思的十二个典型应用案例,和未来机遇畅想
    面对“双十一”这样的大促,品牌方还能多做些什么?
    点云从入门到精通技术详解100篇-面向三维测量的光栅结构光 图像去噪(续)
    关于“& with in |”的警告处理
    流控制传输协议(SCTP)
    一周净赚一套房,“羊了个羊”爆火的产品逻辑可复制吗?
  • 原文地址:https://blog.csdn.net/qq_45303986/article/details/125612547