• C++学习之模板 (二) -----类模板


    由于将函数和类模板放在一块篇幅较大,我们今天将其拆分为两篇博文。

    上篇博文我们讨论了函数模板的简单应用,本篇我们继续讨论模板的另一板块--类模板。

    1)、作用:类模板类似于代码产生器,根据用户输入的类型不同,产生不同的class;

    2)、编译:

      a):检查模板class 的自身语法;

      b):根据用户指定的类型 如 vector<string>,去实例化一个模板类。

    注意: 不是实例化所以的代码,而仅仅实例化用户调用的部分

    类模板:简单实现如下;

     1 #include <iostream>
     2 #include <string>
     3 #include <vector>
     4 using namespace std;
     5 
     6 template <typename T>
     7 class Test
     8 {
     9     public:
    10         Test(const T &s);
    11         void print()const;
    12 
    13     private:
    14         T data_;
    15 };
    16 
    17 template <typename T>//若在类内部,则不必加Test<T>
    18 Test<T>::Test(const T &s)
    19     :data_(s)
    20 { }
    21 
    22 template <typename T> 
    23 void Test<T>::print()const
    24 {
    25     cout << data_ << endl;
    26 }
    27 
    28 int main(int argc, const char *argv[])
    29 {
    30     Test<int> t(12) ; // 比较vector<int> vec
    31     t.print();
    32 
    33     Test<string> t2("world");
    34     t2.print();
    35     
    36     return 0;
    37 }

    注意:STL库中,vector就是一个典型的类模板,vector<int>和vector<string>是两个完全不同的类,同样,vector 不是一个完整的类名,完整的类名如 vector<int> vec;vector必须具备 copy和assignment能力;

     1 #include <iostream>
     2 #include <string>
     3 #include <vector>
     4 using namespace std;
     5 
     6 //class with no copy, no assignment
     7 class Test
     8 {
     9     public:
    10         Test() {};
    11         ~Test() {};
    12 
    13     private:
    14         Test(const Test &);
    15         void operator=(const Test &);
    16 };
    17 
    18 int main(int argc, const char *argv[])
    19 {
    20     vector<Test> vec; //运行此句时,没有产生错误
    21     Test t;
    22 
    23     vec.push_back(t);//此句产生错误。vector必须具备 copy和assignment 能力
    24     return 0;
    25 }

     2):下面我们用stack栈的简单实现来说明类模板的一些问题;

     1 //Stack.hpp
     2 #ifndef STACK_H_
     3 #define STACK_H_
     4 
     5 #include <vector>
     6 #include <stdexcept>
     7 
     8 template <typename T>
     9 class Stack
    10 {   
    11     public:
    12         void push(const T &t);
    13         void pop();//出栈
    14         T top()const; //查看栈顶
    15         bool empty()const 
    16         { return elems_.empty(); }
    17 
    18     private:
    19         std::vector<T> elems_;
    20 };
    21 
    22 template <typename T>
    23 void Stack<T>::push(const T &t)//将t放入vector中
    24 {
    25     elems_.push_back(t);
    26 }
    27 
    28 template <typename T>
    29 void Stack<T>::pop()
    30 {
    31     if(! elems_.empty())
    32         elems_.pop_back();
    33     else
    34         throw std::out_of_range("out of range");
    35 }
    36 
    37 template <typename T>
    38 T Stack<T>::top()const
    39 {
    40     if(! elems_.empty())
    41         return elems_.back();
    42     else
    43         throw std::out_of_range("out of range");
    44 }
    45 #endif

    main.cpp

     1 //main.cpp
     2 #include "Stack.hpp"
     3 #include <iostream>
     4 #include <string>
     5 #include <vector>
     6 using namespace std;
     7 
     8 int main(int argc, const char *argv[])
     9 {
    10     try
    11     {
    12         Stack<int> st;
    13         st.push(7);
    14         cout << st.top() << endl;
    15 
    16         st.pop();
    17         st.pop(); //throw
    18     }
    19     catch(exception &e)
    20     {
    21         cout << e.what()<< endl; 
    22     }
    23     return 0;
    24 }

    注意以上我们将Stack 的声明与定义放在同一个文件中,原因是:将Stack 拆分成 h 和cpp 文件,构建时产生了链接错误;

    a):模板的调用时机和代码的实例化必须放在同一时期;

    b):编译stack.cpp时,编译器找不到任何用户调用的代码,所以得到的 stack.o 文件为空, 使用 nm -A stack.o | grep (函数)

    c): 编译main.cpp时,编译器获取用户的调用,了解到应该去实例化 特定部分 代码 ,但是main.cpp中仅包含 .h 文件,编译器只能找到 模板的某些函数的声明,找不到其定义及实现。 所以推迟到 链接时期;

    d);链接时期,由于 stack.o 文件为空,需要链接的代码没有产生。。

    3);模板的特化:

     1 //模板的特例化
     2 #include "Stack.hpp"
     3 #include <iostream>
     4 #include <deque>
     5 using namespace std;
     6 
     7 template <> //模板特化
     8 class Stack<string>
     9 {
    10     public:
    11         void push(const string &s)
    12         {
    13             elems_.push_back(s);
    14         }
    15 
    16         void pop()
    17         {
    18             elems_.pop_back();
    19         }
    20         string top()const
    21         {
    22             return elems_.back();
    23         }
    24         bool empty()const
    25         {
    26             return elems_.empty();
    27         }
    28     private:
    29         std::deque<string>  elems_;
    30 };
    31 
    32 int main(int argc, const char *argv[])
    33 {
    34     try
    35     {
    36         Stack<string> st;
    37         st.push("hello");
    38     }
    39     catch(exception &e)
    40     {
    41         cout << e.what() << endl;
    42     }
    43 
    44     return 0;
    45 }

    4):模板参数不仅可以为 类型, 而且可以为非类型(数值),需要注意的是,数值也是类名的一部分,例如 Stack<int, 5 > 和 Stack<int , 10> 不是同一类型。因此,二者的对象无法相互赋值。

    缺省的模板参数:

    Stack.hpp

     1 //Stack.hpp
     2 #ifndef STACK_H_
     3 #define STACK_H_
     4 
     5 #include <vector>
     6 #include <stdexcept>
     7 
     8 //缺省的模板参数
     9 template <typename T, typename CONT = std::vector<T> >
    10 class Stack
    11 {   
    12     public:
    13         void push(const T &t);
    14         void pop();//出栈
    15         T top()const; //查看栈顶
    16         bool empty()const 
    17         { return elems_.empty(); }
    18 
    19     private:
    20         CONT elems_;
    21 };
    22 
    23 template <typename T,typename CONT>
    24 void Stack<T,CONT>::push(const T &t)//将t放入vector中
    25 {
    26     elems_.push_back(t);
    27 }
    28 
    29 template <typename T,typename CONT >
    30 void Stack<T,CONT>::pop()
    31 {
    32     if(! elems_.empty())
    33         elems_.pop_back();
    34     else
    35         throw std::out_of_range("out of range");
    36 }
    37 template <typename T,typename CONT>
    38 T Stack<T,CONT>::top()const
    39 {
    40     if(! elems_.empty())
    41         return elems_.back();
    42     else
    43         throw std::out_of_range("out of range");
    44 }
    45 #endif

    main.cpp

     1 #include "Stack.hpp"
     2 #include <iostream>
     3 #include <deque>
     4 using namespace std;
     5 
     6 int main(int argc, const char *argv[])
     7 {
     8     try
     9     {
    10         Stack<int> st;
    11         st.push(7);
    12         cout << st.top() << endl;
    13         st.pop();
    14     
    15         Stack<string, deque<string> > st2;
    16         st2.push("hello");
    17         st2.push("world");
    18         
    19         while(!st2.empty())
    20         {
    21             cout << st2.top() << endl;
    22             st2.pop();
    23         }
    24     }
    25     catch(exception &e)
    26     {
    27         cout << e.what()<< endl; 
    28     }
    29     return 0;
    30 }

    ------------

    非类型模板实现如下:

    Stack.hpp

     1 #ifndef STACK_H_
     2 #define STACK_H_
     3 
     4 #include <vector>
     5 #include <stdexcept>
     6 
     7 //非类型模板形参--->此处int
     8 template <typename T, int MAXSIZE>
     9 class Stack
    10 {   
    11     public:
    12         Stack();
    13         void push(const T &t);
    14         void pop();//出栈
    15         T top()const; //查看栈顶
    16         
    17         bool empty()const 
    18         { return numElems_ == 0; }
    19         bool full()const 
    20         { return numElems_ ==MAXSIZE; }
    21 
    22     private:
    23         T elems_[MAXSIZE];
    24         int numElems_;//当前元素数量
    25 };
    26 
    27 template <typename T, int MAXSIZE >
    28 Stack<T,MAXSIZE>::Stack()
    29     :numElems_(0)
    30 {
    31 
    32 }
    33 template <typename T, int MAXSIZE >
    34 void Stack<T,MAXSIZE>::push(const T &elem)//将t放入vector中
    35 {
    36     if(full())//成员函数的调用
    37         throw std::runtime_error("full");
    38     elems_[numElems_++] =elem ;
    39 }
    40 
    41 template <typename T, int MAXSIZE >
    42 void Stack<T,MAXSIZE>::pop()
    43 {
    44     if(!empty())
    45         --numElems_;//数据还存在
    46     else
    47         throw std::out_of_range("out of range");
    48 }
    49 
    50 template <typename T, int MAXSIZE >
    51 T Stack<T,MAXSIZE>::top()const
    52 {
    53     return elems_[numElems_ -1];
    54 }
    55 #endif

    main.cpp:

     1 #include "Stack.hpp"
     2 #include <iostream>
     3 #include <deque>
     4 using namespace std;
     5 
     6 int main(int argc, const char *argv[])
     7 {
     8     try
     9     {
    10         Stack<int, 5> st;
    11         st.push(14);
    12         st.push(34);
    13         st.push(45);
    14         st.push(9);
    15 
    16         cout << st.empty()<< endl;
    17 
    18         Stack<int, 10> st2; // st 与  st2 类型不同
    19     }
    20     catch(exception &e)
    21     {
    22         cout << e.what()<< endl; 
    23     }
    24     return 0;
    25 }
  • 相关阅读:
    Python服务Dokcer化并k8s部署实例
    Docker Machine
    Docker使用Portainer搭建可视化界面
    三小时攻克 Kubernetes!
    Docker使用pipework配置本地网络
    使用kubeadm安装kubernetes1.12.2版本脚本【h】
    rsync详解之exclude排除文件(转)
    linux生成指定大小的文件(转)
    chown将指定文件的拥有者改为指定的用户或组(转)
    Linux系统分析命令总结
  • 原文地址:https://www.cnblogs.com/xfxu/p/4001370.html
Copyright © 2020-2023  润新知