• C++之函数模板、类模板、模板的特化


    目录

    1.什么是模板?

    2.类模板的定义如下:

    3.模板分类?

    1.模板参数有两种:

    2.模板的类型

    1.函数模板

     2.类模板

    4.模板实例化

     5.模板实现链栈

    1.C语言版

    2.C++版本                         


    1.什么是模板?

    模板是c++的一种特性,允许函数或者类(对象)通过泛型(generic types)的形式表现或者运行模板可以使得函数或类在对应不同的类型(types)的时候正常工作,而无需为每一种类型分别写一份代码。

    为了代码重用,代码就必须是通用的;通用的代码就必须不受数据类型的限制。那么我们可以把数 据类型改为一个设计参数。这种类型的程序设计称为参数化(parameterize) 程序设计。软件模块由模板 (template) 构造。 包括函数模板(function template)和类模板(class template)。

    2.类模板的定义如下:

    1. template<类型模板参数表>
    2. class 类名
    3. {
    4. …… //类声明体
    5. }; //再次指出分号不可少
    6. template<类型模板参数表>
    7. 返回类型 类名<模板参数表>::成员函数名1(形参表)
    8. {
    9. ……;//成员函数定义体
    10. }
    11. ……
    12. template<类型模板参数表>
    13. 返回类型 类名<模板参数表>::成员函数名n(形参表)
    14. {
    15. ……;//成员函数n定义体
    16. }
    17. //类型替换的过程被称为模板实例化 template instantiation
    18. 1

    3.模板分类?

    1.模板参数有两种:

    模板类型参数和模板非类型参数

    2.模板的类型

    1.函数模板

    函数模板是参数化的一族函数(a famliy of functions)

    通过函数模板,可以实例化一系类函数,这些函数都给予同一套模板框架,但是作用在不通类型的参数上

    示例 :(针对不同的数据类型 比较两个数据的大小)

    求最大值:int型、char型。double型等等

    1. int Max(int a, int b)
    2. {
    3. return a > b ? a : b;
    4. }
    5. double Max(double a, double b)
    6. {
    7. return a > b ? a : b;
    8. }
    9. char Max(char a, char b)
    10. {
    11. return a > b ? a : b;
    12. }
    13. void main()
    14. {
    15. cout << Max(5, 3) << endl;
    16. cout << Max(5.3, 7.3) << endl;
    17. cout << Max('C', 'c') << endl;
    18. }

    模板参数是由传递给模板函数的实参决定的

    不允许自动类型转换:每个T必须严格匹配

    使用模板

    1. template<class T> //函数模板--经过类型参数化--->模板函数
    2. T Max(T a, T b)
    3. {
    4. return a > b ? a : b;
    5. }

     //模板的特化--具体化

    1. template<>
    2. const char* Max(const char* a, const char* b)
    3. {
    4. cout << "const char* Max" << endl;
    5. return strcmp(a, b) > 0 ? a : b;
    6. }

    主函数

    1. void main()
    2. {
    3. cout << Max(4, 6) << endl; //类型参数化 int
    4. cout << Max(3.4, 1.2) << endl; //double
    5. cout << Max('a', '1') << endl; //char
    6. cout << Max("333", "555") << endl; //const char*
    7. }

    运行结果

     2.类模板

    与函数模板类似,类也可以通过参数泛化,从而可以构建出一族不同的类实例(对象)

    类模板实参可以是某一类型或常量(仅限int或enum)

    类模板特化

    允许对一个类模板的某些模板参数类型做特化

    特化的作用和好处

    对于某种特殊的类型,可能可以做些特别的优化或提供不同的实现

    避免在实例化的时候引起一些可能不好的行为

    特化一个类模板的时候也意味着需要特化其所有参数化的成员函数

    1. template<class T>
    2. class A
    3. {
    4. public:
    5. A(T i) :m_i(i) {}
    6. void print()
    7. {
    8. cout << "m_i = " << m_i << endl;
    9. }
    10. private:
    11. T m_i;
    12. };
    13. //vector list stack queue
    14. template<>
    15. class A<const char*>
    16. {
    17. public:
    18. A(const char* i)
    19. {
    20. cout << "A const char*" << endl;
    21. m_i = new char[strlen(i) + 1];
    22. strcpy_s(m_i, strlen(i) + 1, i);
    23. }
    24. void print()
    25. {
    26. cout << "A::m_i = " << m_i << endl;
    27. }
    28. ~A()
    29. {
    30. delete[]m_i;
    31. }
    32. private:
    33. char* m_i;
    34. };
    35. void main()
    36. {
    37. A<int> a(4); //将int当成参数传递给模板中的T--》模板类
    38. a.print();
    39. A<char> b('6');
    40. b.print();
    41. A<double> c(3.5);
    42. c.print();
    43. A<const char*> d("helloworld");
    44. d.print();
    45. }

    4.模板实例化

    模板的声明(declaration)其实并未给出一个函数或者类的完全定义(definition),只是提供了一个函数或者类的语法框架(syntactical skeleton)

    实例化是指从模板构建出一个真正的函数或者类的过程。用具体类型代替模板参数的过程叫做实例化;从而产生一个模板实例。

    如果实例化一种类型,而该类型并不支持函数所使用的操作,那么就会导致一个编译错误。

    实例化有两种类型
    1:显示实例化-在代码中明确指定要针对哪种类型进行实例化

    2:隐式实例化-在首次使用时根据具体情况使用一种合适的类型进行实例化

    1. #include
    2. bool great(char a, char b)
    3. {
    4. return a > b;
    5. }
    6. class Great
    7. {
    8. public:
    9. bool operator()(char a, char b)
    10. {
    11. return a > b;
    12. }
    13. };
    14. template<class T>
    15. class GREAT
    16. {
    17. public:
    18. bool operator()(T a, T b)
    19. {
    20. return a > b;
    21. }
    22. };
    23. void main()
    24. {
    25. //int a[] = { 7,6,8,9,0,2,2,3,4,5,6,7 };
    26. char a[] = { '1','a','h','5','3','2','d','k','v','0','x' };
    27. int n = sizeof(a) / sizeof(a[0]);
    28. //sort(a, a + n); //将a到a+n从小到大进行排序---模板
    29. //sort(a, a + n, greater()); //用的库中的greater
    30. //sort(a, a + n, great);
    31. //sort(a, a + n, Great()); //调用Great类中的()重载
    32. sort(a, a + n, GREAT<char>());
    33. for (int i = 0; i < n; i++)
    34. cout << a[i] << " ";
    35. cout << endl;
    36. }

     5.模板实现链栈

    1.C语言版

    1. class MyStack
    2. {
    3. private:
    4. struct StackNode
    5. {
    6. int data;
    7. StackNode* next;
    8. public:
    9. StackNode(int val = 0, StackNode* p = nullptr)
    10. :data(val), next(p) {}
    11. };
    12. private:
    13. StackNode* top; // heap;
    14. int cursize;
    15. void clone(const MyStack& s)
    16. {
    17. Clear();
    18. cursize = s.cursize;
    19. StackNode* p = s.top;
    20. if (p == nullptr) return;
    21. top = new StackNode(p->data); //
    22. StackNode* tail = top;
    23. p = p->next;
    24. while (p != nullptr)
    25. {
    26. tail = tail->next = new StackNode(p->data);
    27. p = p->next;
    28. }
    29. }
    30. public:
    31. MyStack() :top(nullptr), cursize(0) {}
    32. MyStack(const MyStack& s)
    33. :top(nullptr), cursize(s.cursize)
    34. {
    35. clone(s);
    36. } // MyStack yous(mys);
    37. MyStack& operator=(const MyStack& s)
    38. {
    39. if (this != &s)
    40. {
    41. clone(s);
    42. }
    43. return *this;
    44. } // mys = hes;// top;
    45. ~MyStack()
    46. {
    47. Clear();
    48. }
    49. void Clear()
    50. {
    51. while (top != nullptr)
    52. {
    53. StackNode* q = top;
    54. top = q->next;
    55. delete q;
    56. }
    57. cursize = 0;
    58. }
    59. int Size() const { return cursize; }
    60. bool Empty() const { return Size() == 0; }
    61. void Push(int val)
    62. {
    63. top = new StackNode(val, top); // 1 2 heap
    64. cursize += 1;
    65. }
    66. int& Top() { return top->data; }
    67. const int& Top()const { return top->data; }
    68. void Pop()
    69. {
    70. StackNode* q = top;
    71. top = q->next;
    72. delete q;
    73. cursize -= 1;
    74. }
    75. bool GetTop(int& val)
    76. {
    77. if (Empty()) return false;
    78. val = top->data;
    79. StackNode* q = top;
    80. top = q->next;
    81. delete q;
    82. cursize -= 1;
    83. return true;
    84. }
    85. };
    86. int main()
    87. {
    88. MyStack mys;
    89. for (int i = 0; i < 10; ++i)
    90. {
    91. mys.Push(i);
    92. }
    93. MyStack ys(mys);
    94. }

    2.C++版本                         

    1. template<class T> //
    2. class MyStack
    3. {
    4. public:
    5. struct StackNode
    6. {
    7. T data; // int data;
    8. StackNode* next;
    9. public:
    10. StackNode(const T& val = T(), StackNode* p = nullptr)
    11. :data(val), next(p) {}
    12. };
    13. private:
    14. StackNode* top; // heap;
    15. int cursize;
    16. void clone(const MyStack& s)
    17. {
    18. Clear();
    19. cursize = s.cursize;
    20. StackNode* p = s.top;
    21. if (p == nullptr) return;
    22. top = new StackNode(p->data); //
    23. StackNode* tail = top;
    24. p = p->next;
    25. while (p != nullptr)
    26. {
    27. tail = tail->next = new StackNode(p->data);
    28. p = p->next;
    29. }
    30. }
    31. public:
    32. MyStack() :top(nullptr), cursize(0) {}
    33. MyStack(const MyStack& s)
    34. :top(nullptr), cursize(s.cursize)
    35. {
    36. clone(s);
    37. } // MyStack yous(mys);
    38. MyStack& operator=(const MyStack& s)
    39. {
    40. if (this != &s)
    41. {
    42. clone(s);
    43. }
    44. return *this;
    45. } // mys = hes;// top;
    46. ~MyStack()
    47. {
    48. Clear();
    49. }
    50. void Clear()
    51. {
    52. while (top != nullptr)
    53. {
    54. StackNode* q = top;
    55. top = q->next;
    56. delete q;
    57. }
    58. cursize = 0;
    59. }
    60. int Size() const { return cursize; }
    61. bool Empty() const { return Size() == 0; }
    62. void Push(const T& val) // T
    63. {
    64. top = new StackNode(val, top); // 1 2 heap
    65. cursize += 1;
    66. }
    67. T& Top() { return top->data; }
    68. const T& Top()const { return top->data; }
    69. void Pop()
    70. {
    71. StackNode* q = top;
    72. top = q->next;
    73. delete q;
    74. cursize -= 1;
    75. }
    76. bool GetTop(T& val);
    77. };
    78. template<class T>
    79. bool MyStack::GetTop(T& val)
    80. {
    81. if (Empty()) return false;
    82. val = top->data;
    83. StackNode* q = top;
    84. top = q->next;
    85. delete q;
    86. cursize -= 1;
    87. return true;
    88. }
    89. int main()
    90. {
    91. MyStack<int> imys;
    92. MyStack<char> cmys;
    93. MyStack pmys;
    94. MyStack<int>::StackNode x;
    95. for (int i = 0; i < 3; ++i)
    96. {
    97. pmys.Push(Point(i, i + 10));
    98. }
    99. Point px;
    100. while (pmys.GetTop(px))
    101. {
    102. cout << px.PointX() << " : " << px.PointY() << endl;
    103. }
    104. }

  • 相关阅读:
    零基础自学javase黑马课程第七天
    时间序列预测(9) — Informer源码详解与运行
    linux 配置静态IPv6地址
    实现最简的内核模块
    HTML基础知识
    柯桥英语口语学校,商务英语BEC考前须知
    【LeetCode-简单题KMP】459. 重复的子字符串
    反弹Shell
    dp线段树优化-最大子段和
    Cadence IC618使用
  • 原文地址:https://blog.csdn.net/m0_59052131/article/details/127822226