当前位置:   article > 正文

C++模板的使用_c++类模板的使用

c++类模板的使用

目录

1、模板的概述:

2、函数模板

2.1、函数模板的定义方式

 2.2、函数模板注意事项

2.3、函数模板和普通函数区别

2.4、函数模板的重载

2.5、函数模板的非类型参数

2.6、多文件编程实现函数模板

3、类模板

3.1、类模板的定义

3.2、类模板和函数模板区别

3.3、类模板的友元函数

3.4、类模板的继承

3.5、类模板对象作为函数参数


1、模板的概述:

        C++提供了函数模板(function template.)所谓函数模板,实际上是建立一个通用函数,函数类型和形参类型不具体制定,用一个虚拟的类型来代表。这个通用函数就称为函数模板。凡是函数体相同的函数都可以用这个模板代替,不必定义多个函数,只需在模板中定义一次即可。在调用函数时系统会根据实参的类型来取代模板中的虚拟类型,从而实现不同函数的功能。C++提供两种模板机制:函数模板和类模板。
总结:
C++面向对象编程思想:封装、继承、多态
C++泛型编程思想:模板
模板的分类:函数模板、类模板
将功能相同,类型不同的函数(类)的类型抽象成虚拟的类型。当调用函数(类实例化对象)的时候,编译器自动将虚拟的类型具体化。这个就是函数模板(类模板)。 

2、函数模板


2.1、函数模板的定义方式

关键字:template

#include <iostream>
#include <string>

using namespace std;
template <typename T>
void swap_all(T&x,T&y)        //函数作用:通过使用函数模板交换任意类型的变量的值
{
    T temp = x;
    x = y;
    y = temp;
}

int main()

{

        int a = 10,b = 20;

        swap(a,b);        //隐式类型推导

        //swap<int>(a,b);        //显示类型推导(推荐使用)

        cout << "a = " <<a<<" b = "<<b<<endl;

        return 0;

}

 2.2、函数模板注意事项

        (1)显示类型推导参数和推导的类型必须一致。
        (2)如果有普通函数和模板函数都能匹配优先调用模板函数,如在调用时用显示调用(省略类型的方式  swap_all<>(1,2))则会调用模板函数。

2.3、函数模板和普通函数区别

    (1)函数只可以有一种数据类型相匹配,模板有多种类型相匹配
    (2)隐式推导优先使用普通函数,只有普通函数不匹配才使用函数模板
    (3)函数模板只有在调用时,才会构建函数,而普通函数是在编译时。
    (4)普通函数调用时候可以发生自动类型转换,而函数模板不行。  

2.4、函数模板的重载

        和普通函数的重载相似。也是同一个作用域类函数名相同参数列表不同。
        以下是参数顺序不同的重载:      

  1. template <class T1,class T2>void swap1(T2 a,T1 b)
  2. template <class T1,class T2>void swap1(T1 a,T2 b)

         注意,在函数参数顺序不同的重载中,实例化的时候不可以是相同类型。
        例如  swap1<int ,int >(1,2)则没法匹配哪个函数。
     以下是参数个数不同的重载
         template <class T1,class T2>   void swap1(T1 a,T2 b)
         template <typename T2>  void swap1(T2 t)
         传入不同的参数,调用不同的版本

2.5、函数模板的非类型参数

     希望传入函数一个特定的确定参数,但不希望放在小括号中。可以通过非类型参数实现。在模板<>中加了一个参数,但这个参数不是类型参数,是具体的某一个值。
     格式:template<class T,基本数据类型 变量名>
               返回值 函数名(T& 变量)
      例如:template <class T,int size>
                 void showArr(T* arr);
      注意:在上例子中,size是通过模板传入到函数中,可以当做普通变量使用
                非类型参数都是常量,在函数中不允许修改,只可以使用,定义非类型参数变量时候,需要加const。   
 例子: 写一个函数模板,打印数组的所有内容。(但不可以在参数中加入数组大小)。

  1. template<class Y,int size>
  2. void show_size(Y*x)
  3. {
  4. for(int i = 0;i<size;i++)
  5. {
  6. cout<<x[i]<<" ";
  7. }
  8. cout<<endl;
  9. }
  10. int main()
  11. {
  12. int arr[5]={2,4,6,8,10};
  13. const int arrSize = sizeof(arr)/sizeof(arr[0]);
  14. show_size<int,arrSize>(arr);
  15. return 0;
  16. }

2.6、多文件编程实现函数模板

        在定义函数或者类的时候,会.h和cpp文件,定义和申明分开。但是在C++中使用模板这样做会出现连接错误,原因:函数模板是在调用时确定的版本,而调用时.h中没有函数实现,出现连接错误,找不到函数体,如果分开后,编译会出现连接错误。

解决方法:

     (1)在main中#include <xxx.h>  和 #include <xx.cpp>
     (2)模板的定义和申明都放在.h头文件中。

3、类模板

3.1、类模板的定义

     建立一个通用的类,如果希望成员变量的类型是任意的,可以用类模板实现。类模板不是一个实际的类型,是虚拟的,和ppt模板一样,实例化的时候才会构建类。
     格式:template<typename T>
               class test { T age; };
      实例化: 类名<类型> 变量名(参数);
代码如下:

  1. template <class t1,class t2>
  2. class person
  3. {
  4. private:
  5. t1 a;
  6. t2 b;
  7. public:
  8. person();
  9. person(t1 a,t2 b);
  10. };
  11. template <class t1,class t2>
  12. person<t1,t2>::person()
  13. {
  14. a = 0;
  15. b = 0;
  16. }
  17. template <class t1,class t2>
  18. person<t1,t2>::person(t1 a, t2 b)
  19. {
  20. this->a = a;
  21. this->b = b;
  22. }
  23. int main(int argc, char *argv[])
  24. {
  25. person<int ,char> p1(10,'a');
  26. return 0;
  27. }

     

3.2、类模板和函数模板区别

        函数模板可以使用隐式类型推导,但类模板不可以,必须显示推导
      类模板在定义template时候,可以加上默认参数。template<class T1,class T2=string>
      在模板中的默认参数类型中,如果所有模板参数都是缺省,但在类进行实例化的时候,尖括号不可以省略

3.3、类模板的友元函数

  1. using namespace std;
  2. template <class t1,class t2>
  3. class person
  4. {
  5. private:
  6. t1 a;
  7. t2 b;
  8. public:
  9. person();
  10. person(t1 a,t2 b);
  11. template <typename t3,typename t4>
  12. friend void show_person(person<t3,t4> &ob);
  13. };
  14. template <class t1,class t2>
  15. person<t1,t2>::person()
  16. {
  17. a = 0;
  18. b = 0;
  19. }
  20. template <class t1,class t2>
  21. person<t1,t2>::person(t1 a, t2 b)
  22. {
  23. this->a = a;
  24. this->b = b;
  25. }
  26. template <typename t3,typename t4>
  27. void show_person(person<t3,t4> &ob) //函数模板做为类模板的友元函数
  28. {
  29. cout<<ob.a<<" "<<ob.b<<endl;
  30. }
  31. int main(int argc, char *argv[])
  32. {
  33. person<int ,char> p1(10,'a');
  34. show_person(p1); //函数模板作为类模板的友元函数的调用
  35. return 0;
  36. }

3.4、类模板的继承

        普通类继承:class son:public father{}
        模板类继承:普通子类继承模板类;
        格式:class 子类:public 父类<指定类型>
        构建对象:和普通对象的构建一样 类名 对象(参数列表);
 
         类模板继承类模板
         格式: template<class T1,class T2>
                     class son: public person<T1,T2> {}

当类模板碰到继承时,需要注意以下几点:

(1)当子类继承的父类是一个类模板时,子类在声明的时候,要指定出父类中T的类型

(2)如果不指定,编译器无法给子类分配内存

(3)如果想灵活指定出父类中T的类型,子类也需为类模板

  1. //类模板与继承
  2. template<class T>
  3. class Base
  4. {
  5. T m;
  6. };
  7. //class Son: public Base //错误,必须要知道父类中的T类型,才能继承给子类
  8. class Son :public Base<int>
  9. {
  10. };
  11. void test01()
  12. {
  13. Son s1;
  14. }
  15. //如果想灵活指定父类中T的类型,子类也需要变成类模板
  16. template<class T1,class T2>
  17. class Son2 : public Base<T2>
  18. {
  19. public:
  20. Son2()
  21. {
  22. cout << "T1的类型为:" << typeid(T1).name() << endl;
  23. cout << "T2的类型为:" << typeid(T2).name() << endl;
  24. }
  25. T1 obj;
  26. };
  27. void test02()
  28. {
  29. Son2<int,char> s2;
  30. }
  31. int main()
  32. {
  33. test02();
  34. system("pause");
  35. return 0;
  36. }

3.5、类模板对象作为函数参数

一共有三种传入方式:

        (1)指定传入的类型:直接显示对象的数据类型

        (2)参数模板化:将对象中的参数变为模板进行传递

        (3)整个类模板化:将这个对象类型模板化进行传递

示例

  1. //类模板对象做函数参数
  2. template<class T1,class T2>
  3. class Person
  4. {
  5. public:
  6. Person(T1 name,T2 age)
  7. {
  8. this->m_Age = age;
  9. this->m_Name = name;
  10. }
  11. void showPerson()
  12. {
  13. cout << "name: " << this->m_Name << " age:" << this->m_Age << endl;
  14. }
  15. T1 m_Name;
  16. T2 m_Age;
  17. };
  18. //1、指定传入类型
  19. void printPerson1(Person<string, int>&p)
  20. {
  21. p.showPerson();
  22. }
  23. void test01()
  24. {
  25. Person<string, int>p("孙悟空", 199);
  26. printPerson1(p);
  27. }
  28. // 2、参数模板化
  29. template<class T1,class T2>
  30. void printPerson2(Person<T1,T2>&p)
  31. {
  32. p.showPerson();
  33. cout << "T1的类型为:" << typeid(T1).name() << endl;
  34. cout << "T2的类型为:" << typeid(T2).name() << endl;
  35. }
  36. void test02()
  37. {
  38. Person<string, int>p("猪八戒", 90);
  39. printPerson2(p);
  40. }
  41. // 3、整个类模板化
  42. template<class T>
  43. void printPerson3(T &p)
  44. {
  45. p.showPerson();
  46. cout << "T的类型为:" << typeid(T).name() << endl;
  47. }
  48. void test03()
  49. {
  50. Person<string, int>p("唐僧", 60);
  51. printPerson3(p);
  52. }
  53. int main()
  54. {
  55. test01();
  56. test02();
  57. test03();
  58. system("pause");
  59. return 0;
  60. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/576709
推荐阅读
相关标签
  

闽ICP备14008679号