• 【C++】模板template


    前言:本教程使用到的工具是vs2010

    目录

    为什么要使用模板? 

    template模板

            函数模板

            类的模板

    template模板的本质 

    总结


    为什么要使用模板? 

            我们先来大概了解一下模板的概念,下面是菜鸟教程对于模板给出的解释:

            模板是泛型编程的基础,泛型编程即以一种独立于任何特定类型的方式编写代码。

            模板是创建泛型类或函数的蓝图或公式。库容器,比如迭代器和算法,都是泛型编程的例子,它们都使用了模板的概念。

            每个容器都有一个单一的定义,比如 向量,我们可以定义许多不同类型的向量,比如 vector  或 vector

            知道了模板的基本概念之后,我们先来看一段代码:

    1. #include
    2. #include
    3. void Sort(int* arr, int nLength)
    4. {
    5. int ii;
    6. int kk;
    7. for(ii=0;ii-1;ii++)
    8. {
    9. for(kk=0;kk-1;kk++)
    10. {
    11. if(arr[kk]>arr[kk+1])
    12. {
    13. int temp = arr[kk];
    14. arr[kk] = arr[kk+1];
    15. arr[kk+1] = temp;
    16. }
    17. }
    18. }
    19. }
    20. int main()
    21. {
    22. return 0;
    23. }

            这是一段最简单的冒泡排序代码,看不懂没关系,知道怎么用就行;

            继续往下:

            我们定义一个整型数组,里面存放被打乱了的几个整数,如下:

            然后我们调用函数,如下:

     

            调试:

     

            此时顺序是乱的,单步步过F10一下:

     

            已经重新排序;

            好了,我们现在知道这个函数怎么用了,继续往下看:

            我们知道在C语言中'a'和'b'是可以比较的,因为字符类型其实也就是整型,他们的比较是ascii码值的比较,'a'的ascii码值是97,'b'的是98,'c'的99....以此类推,那么我们是不是可以对字符进行排序呢?

            可以;

            我们复制一下上面的整形冒泡排序代码,改一点就行了,如下:

            我们定义一个字符数组,并进行排序,如下:

            调试:

     

            单步F10:

     

            排序成功!

            虽然我们达到了目的,但是我们违背了面向对象编程设计思想: 提高代码的复用性,减少重复代码的编写;

            但是,template模板可以帮我们解决这个问题,这也就是我们为什么要使用模板的原因了;

    template模板

            template模板又分为函数模板和类模板,我们先讲函数模板;

            函数模板

            函数模板的格式:

            template

            返回值类型 函数名(参数列表)

            {

                    函数体;

            }

            下面我们给我们的冒泡排序函数加上模板:

     

            !!!!注意看图片上的文字!!!!;

            然后把我们想要自适应类型的地方全部换成T就行了,如下:

            下面我们来测试,先测试int类型,如下:

     

            调试:

     

            F10:

     

            没有问题,接着我们测试char类型:

     

            调试:

     

            F10:

             

            没有问题;

            那么这个函数能对自己定义的类型进行排序吗?

            当然可以;

            如下,我们定义一个类:

            我们首先要知道,如果我们想给我们自己定义的类的对象进行排序的话,那么我们肯定要进行运算符重载;

            我们观察一下刚刚冒泡排序的函数,需要比较类的对象大小的地方有哪些:

            我们可以发现,就这一个地方需要对我们类的对象进行比较大小,而且是大于号;

            那么我们只需要重载'>'即可,如下:

            下面我们进行测试,定义对象,并调用模板函数:

     

            调试:

     

            F10:

     

            ok,没有问题;

            template模板成功的帮我们减少了重复代码的编写,提高了代码的复用性;

            类的模板

            先看代码:

    1. #include
    2. #include
    3. template<class T>
    4. class CBase
    5. {
    6. public:
    7. int x;
    8. int y;
    9. char a;
    10. char b;
    11. int MAX()
    12. {
    13. if(x>y) return x;
    14. if(xreturn y;
    15. }
    16. char MIN()
    17. {
    18. if(a>b) return b;
    19. if(areturn a;
    20. }
    21. };
    22. int main()
    23. {
    24. return 0;
    25. }

            定义了一个类,类中有四个成员变量;分别是int型的x、y;char型的a、b;

            然后x和y比较谁大返回谁,a和b比较谁小返回谁;

            我们来分析一下,这个类中大概有几个需要自适应类型的地方:

            我们知道了这个类中大概有两个地方需要自适应类型,那么接下来先声明这个类为模板类: 

            因为我们有两个需要自适应的类型,所以这里的class参数有两个;

            下面我们进行模板的替换:

     

             替换好了,下面我们进行测试:

            定义好对象以后,我们给对象的成员进行赋值:

     

            我们调用比较的成员函数:

     

            我们将鼠标悬停到MAX和MIN上:

     

     

            可以看到,在我们CBase声明之后,编译器就已经知道MAX和MIN函数的类型了;我们接收一下返回值,如下: 

            观察r和t:

     

            没有问题;

            当然在类中的模板中,也是可以比较类的对象的,依旧需要重载运算符,这里我就不演示了;

    template模板的本质 

            下面我们来说一下,template模板的本质:

            代码如下:

    1. #include
    2. #include
    3. class CBase
    4. {
    5. public:
    6. int x;
    7. int y;
    8. CBase(int x,int y)
    9. {
    10. this->x = x;
    11. this->y = y;
    12. }
    13. bool operator>(CBase& right) // 因为我们'>'有两个操作数,左是this指针,那么这里的右操作数只能传一个参数;
    14. {
    15. return this->x > right.x && this->y > right.y; // 返回左操作数大于右操作数的结果,如果左大于右就为真,否则为假,达到了大于号的目的;
    16. }
    17. };
    18. template<class T> // 只需要在这里加上模板声明即可
    19. void Sort(T* arr, int nLength)
    20. {
    21. int ii;
    22. int kk;
    23. for(ii=0;ii-1;ii++)
    24. {
    25. for(kk=0;kk-1;kk++)
    26. {
    27. if(arr[kk]>arr[kk+1])
    28. {
    29. T temp = arr[kk];
    30. arr[kk] = arr[kk+1];
    31. arr[kk+1] = temp;
    32. }
    33. }
    34. }
    35. }
    36. int main()
    37. {
    38. int arr1[5] = {2,1,4,5,3};
    39. char arr2[5] = {'c','b','d','a','e'};
    40. CBase c1(2,2),c2(1,1),c3(4,4),c4(3,3),c5(5,5);
    41. CBase arr3[5] = {c1,c2,c3,c4,c5};
    42. Sort(arr1,5); // 此处下断点
    43. system("pause");
    44. return 0;
    45. }

            首先我们先对arr1进行排序,断点下载Sort;编译、调试、alt+8转到反汇编,如下:

            template模板在底层已经识别了改排序是int类型的排序,这没有问题;

            然后我们将arr2也假如排序,那么template底层会怎么做呢?

     

            编译、调试、alt+8反汇编:

     

            可以看到template模板在底层又重新生成了一个函数,用于char类型的排序;

            那么arr3如果加入排序的话,相比大家也都知道结果了,这里我就不测试了;感兴趣的话可以自己测试一下;

            现在我们可以总结一下template的本质是什么了;

            template模板并没有我们想的那么高大上,就是说仅仅一个函数可以千变万化,其实并不是千变万化也并不是一个函数;

            我们刚刚也看到了,模板的底层就是通过看你传入参数的类型,给你分配一个适用你传入类型的函数,你传入int类型,他就给你一个适用int类型的函数,你传入char他就给你一个适用char类型的函数;如果你连续传入int、char等n个类型进行排序,那么他的底层就会给你分配n个函数,并不是一个函数实现的类型自适应;

    总结

            1、我们使用模板的目的就是为了提高代码的复用性,减少重复代码的编写;

            2、函数模板的底层并不是只有一个函数完成的,它是根据你传入参数的类型,给你分配一个适用你传入类型的函数;如果你连续传入n个类型,他就会给你分配n个函数;

    结语:

            文章讲义到此结束,如果有讲错的地方或者说讲的不好的地方,望指出;感谢大家观看!

  • 相关阅读:
    Vue框架的学习(Vue的基础指令操作一)第二课
    Revit导入CAD翻模丨CAD图层管理控制显示隐藏图层
    PostMan发送请求参数带有路径特殊字符会返回400错误(与URL字符及URL编码值有关)
    【LeetCode】141.环形链表
    LabVIEW中图像显示错误
    网络安全实战:剖析ThinkPHP 5.1.X反序列化漏洞
    数据结构-堆基本应用刷题
    CTF之序列化__toString
    2022年下半年网络规划设计师下午真题及答案解析
    Oracle/PLSQL: Substr Function
  • 原文地址:https://blog.csdn.net/qq_52572621/article/details/127872426