我们以顺序表为例来说明,普通顺序表的定义如下:

  1. typedef int DataType;
  2. //typedef char DataType;
  3. class SeqList
  4. {
  5. private :
  6. DataType* _data ;
  7. int _size ;
  8. int _capacity ;
  9. } ;

模板类也是模板, 必须以 关键字templ ate开头, 后接模板形参表。 模板类一般格式如下:
template<class 形参名 1, class 形参名 2, . . . class 形参名 n>
class 类名
{ . . . } ;

  1. // 以模板方式实现动态顺序表
  2. template<typename T>
  3. class SeqList
  4. {
  5. public :
  6. SeqList() ;
  7. ~ SeqList() ;
  8. private :
  9. int _size ;
  10. int _capacity ;
  11. T* _data ;
  12. } ;
  13. template <typename T>
  14. SeqList <T>: : SeqList()
  15. :
  16. _size()
  17. , _capacity()
  18. , _data(new T[ _capacity] )
  19. {}//注意模板类的类型不是SeqList
  20. template <typename T>
  21. SeqList <T>: : ~ SeqList()
  22. {
  23. delete [] _data ;
  24. }
  25. void test1()
  26. {
  27. SeqList<int > sl1;
  28. SeqList<double > sl2;
  29. }

【 模板类的实例化】
只 要有一种不同的类型, 编译器就会实例化出一个对应的类。
SeqList<int > sl1;
SeqList<double > sl2;
当定义上述两种类型的顺序表时, 编译器会使用int和double分别代替模板形参, 重新编写SeqList类, 最后创建名 为SeqList<int>和SeqList<double>的类。

模板参数--实现容器适配器

  1. template <typename T>
  2. class SeqList
  3. {p
  4. rivate :
  5. int _size ;
  6. int _capacity ;
  7. T* _data ;
  8. } ;
  9. // template <class T, class Container>
  10. template <class T, class Container = SeqList<T> > // 缺省参数
  11. class Stack
  12. {
  13. public :
  14. void Push (const T& x) ;
  15. void Pop () ;
  16. const T& Top() ;
  17. bool Empty () ;
  18. private :
  19. Container _con ;
  20. } ;
  21. void Test()
  22. {
  23. Stack<int> s1;
  24. Stack<int , SeqList<int>> s2 ;
  25. // 思考下面这种使用场景会怎样?
  26. Stack<int , SeqList<char>> s3 ;
  27. }

为了避免上述问题的存在用下面的方法:

模板的模板参数--容器适配器

  1. template <typename T>
  2. class SeqList
  3. {p
  4. rivate :
  5. int _size ;
  6. int _capacity;
  7. T* _data ;
  8. } ;
  9. // template <class T, template<class> class Container>
  10. template <class T, template<class> class Container = SeqList> // 缺省参数
  11. class Stack
  12. {
  13. public :
  14. void Push(const T& x ) ;
  15. void Pop() ;
  16. const T& Top() ;
  17. bool Empty() ;
  18. private :
  19. Container<T > _con;
  20. } ;
  21. void Test()
  22. {
  23. Stack<int> s1;
  24. Stack<int , SeqList> s2;
  25. }

非类型的类模板参数

  1. // 静态顺序表
  2. //template<typename T, size_t MAX_SIZE>
  3. template <typename T, size_t MAX_SIZE = > //带缺省模板参数
  4. class SeqList
  5. {
  6. public :
  7. SeqList() ;
  8. private :
  9. T _array [MAX_SIZE] ;
  10. int _size ;
  11. } ;
  12. template <typename T, size_t MAX_SIZE>
  13. SeqList <T, MAX_SIZE>: : SeqList()
  14. : _size()
  15. {}
  16. void Test()
  17. {
  18. SeqList<int> s1;
  19. SeqList<int , > s2;
  20. }

注意: 浮点数和类对象是不允许作为非类型模板参数的。

类模板的特化

类模板的特化:与函数模板类似,当类模板内需要对某些类型进行特别处理时,使用类模板的特化。例如:

  1. // general version
  2. template<class T>
  3. class Compare
  4. {
  5. public:
  6. static bool IsEqual(const T& lh, const T& rh)
  7. {
  8. std::cout <<"in the general class..." <<std::endl;
  9. return lh == rh;
  10. }
  11. };
  12. // specialize for float
  13. template<>
  14. class Compare<float>
  15. {
  16. public:
  17. static bool IsEqual(const float& lh, const float& rh)
  18. {
  19. std::cout <<"in the float special class..." <<std::endl;
  20.  
  21. return std::abs(lh - rh) < 10e-;
  22. }
  23. };
  24. // specialize for double
  25. template<>
  26. class Compare<double>
  27. {
  28. public:
  29. static bool IsEqual(const double& lh, const double& rh)
  30. {
  31. std::cout <<"in the double special class..." <<std::endl;
  32.  
  33. return std::abs(lh - rh) < 10e-;
  34. }
  35. };
  36. int main(void)
  37. {
  38. Compare<int> comp1;
  39. std::cout <<comp1.IsEqual(, ) <<std::endl;
  40. std::cout <<comp1.IsEqual(, ) <<std::endl;
  41.  
  42. Compare<float> comp2;
  43. std::cout <<comp2.IsEqual(3.14, 4.14) <<std::endl;
  44. std::cout <<comp2.IsEqual(, ) <<std::endl;
  45.  
  46. Compare<double> comp3;
  47. std::cout <<comp3.IsEqual(3.14159, 4.14159) <<std::endl;
  48. std::cout <<comp3.IsEqual(3.14159, 3.14159) <<std::endl;
  49. return ;
  50. }

全特化

还是以顺序表为例说明

  1. 全特化
  2. template <typename T>
  3. class SeqList
  4. {
  5. public :
  6. SeqList() ;
  7. ~ SeqList() ;
  8. private :
  9. int _size ;
  10. int _capacity ;
  11. T* _data ;
  12. } ;
  13. template<typename T>
  14. SeqList <T>: : SeqList()
  15. : _size()
  16. , _capacity()
  17. , _data(new T[ _capacity] )
  18. {
  19. cout<<"SeqList<T>" <<endl;
  20. }
  21. template<typename T>
  22. SeqList <T>: : ~ SeqList()
  23. {
  24. delete[] _data ;
  25. }
  26. template <>
  27. class SeqList <int>
  28. {
  29. public :
  30. SeqList(int capacity) ;
  31. ~ SeqList() ;
  32. private :
  33. int _size ;
  34. int _capacity ;
  35. int* _data ;
  36. } ;
  37. // 特化后定义成员 函数不再需要模板形参
  38. SeqList <int>: : SeqList(int capacity)
  39. : _size()
  40. , _capacity(capacity )
  41. , _data(new int[ _capacity] )
  42. {
  43. cout<<"SeqList<int>" <<endl;
  44. }
  45. // 特化后定义成员 函数不再需要模板形参
  46. SeqList <int>: : ~ SeqList()
  47. {
  48. delete[] _data ;
  49. }
  50. void test1 ()
  51. {
  52. SeqList<double > sl2;
  53. SeqList<int > sl1() ;
  54. }
  1. 偏特化( 局部特化)
  2. template <typename T1, typename T2>
  3. class Data
  4. {
  5. public :
  6. Data() ;
  7. private :
  8. T1 _d1 ;
  9. T2 _d2 ;
  10. } ;
  11. template <typename T1, typename T2>
  12. Data<T1 , T2>: : Data()
  13. {
  14. cout<<"Data<T1, T2>" <<endl;
  15. }
  16. // 局部特化第二个参数
  17. template <typename T1>
  18. class Data <T1, int>
  19. {
  20. public :
  21. Data() ;
  22. private :
  23. T1 _d1 ;
  24. int _d2 ;
  25. } ;
  26. template <typename T1>
  27. Data<T1 , int>: : Data()
  28. {
  29. cout<<"Data<T1, int>" <<endl;
  30. }

下面的例子可以看出, 偏特化并不仅仅是指特化部分参数, 而是针对模板参数更进一步的条件限制所设计出来的一个特化版本。

  1. // 局部特化两个参数为指针类型
  2. template <typename T1, typename T2>
  3. class Data <T1*, T2*>
  4. {
  5. public :
  6. Data() ;
  7. private :
  8. T1 _d1 ;
  9. T2 _d2 ;
  10. T1* _d3 ;
  11. T2* _d4 ;
  12. } ;
  13. template <typename T1, typename T2>
  14. Data<T1 *, T2*>: : Data()
  15. {
  16. cout<<"Data<T1*, T2*>" <<endl;
  17. }
  18. // 局部特化两个参数为引 用
  19. template <typename T1, typename T2>
  20. class Data <T1&, T2&>
  21. {
  22. public :
  23. Data(const T1& d1, const T2& d2) ;
  24. private :
  25. const T1 & _d1;
  26. const T2 & _d2;
  27. T1* _d3 ;
  28. T2* _d4 ;
  29. } ;
  30. template <typename T1, typename T2>
  31. Data<T1 &, T2&>: : Data(const T1& d1, const T2& d2)
  32. : _d1(d1 )
  33. , _d2(d2 )
  34. {
  35. cout<<"Data<T1&, T2&>" <<endl;
  36. }
  37. void test2 ()
  38. {
  39. Data<double , int> d1;
  40. Data<int , double> d2;
  41. Data<int *, int*> d3;
  42. Data<int&, int&> d4(, ) ;
  43. }

模板的全特化和偏特化都是在已定义的模板基础之上,不能单独存在。

关于特化的总结:

特化的分类

针对特化的对象不同,分为两类:函数模板的特化类模板的特化

  • 函数模板的特化:当函数模板需要对某些类型进行特化处理,称为函数模板的特化。

  • 类模板的特化:当类模板内需要对某些类型进行特别处理时,使用类模板的特化。

特化整体上分为全特化偏特化 
全特化就是模板中模板参数全被指定为确定的类型。全特化也就是定义了一个全新的类型,全特化的类中的函数可以与模板类不一样。

偏特化就是模板中的模板参数没有被全部确定,需要编译器在编译时进行确定。

全特化的标志就是产生出完全确定的东西,而不是还需要在编译期间去搜寻适合的特化实现,貌似在我的这种理解下,全特化的 东西不论是类还是函数都有这样的特点,

  1. 模板函数只能全特化,没有偏特化(重载)。

  2. 模板类是可以全特化和偏特化的。

很多时候,我们既需要一个模板能应对各种情形,又需要它对于某个特定的类型(比如bool)有着特别的处理,这种情形下特化就是非常必要的。

模板总结

【 优点】
模板复用了 代码, 节省资源, 更快的迭代开发, C++的标准模板库(STL) 因此而产生。
增强了 代码的灵活性。

【 缺点】
模板让代码变得凌乱复杂, 不易维护, 编译代码时间变长。
出现模板编译错误时, 错误信息非常凌乱, 不易定位错误。

C++—模板(2)类模板与其特化的更多相关文章

  1. 【校招面试 之 C/C++】第2题 函数模板、类模板、特化、偏特化

    1.C++模板 说到C++模板特化与偏特化,就不得不简要的先说说C++中的模板.我们都知道,强类型的程序设计迫使我们为逻辑结构相同而具体数据类型不同的对象编写模式一致的代码,而无法抽取其中的共性,这样 ...

  2. C++解析(26):函数模板与类模板

    0.目录 1.函数模板 1.1 函数模板与泛型编程 1.2 多参数函数模板 1.3 函数重载遇上函数模板 2.类模板 2.1 类模板 2.2 多参数类模板与特化 2.3 特化的深度分析 3.小结 1. ...

  3. [Reprint] C++函数模板与类模板实例解析

    这篇文章主要介绍了C++函数模板与类模板,需要的朋友可以参考下   本文针对C++函数模板与类模板进行了较为详尽的实例解析,有助于帮助读者加深对C++函数模板与类模板的理解.具体内容如下: 泛型编程( ...

  4. C++_进阶之函数模板_类模板

     C++_进阶之函数模板_类模板 第一部分 前言 c++提供了函数模板(function template.)所谓函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体制定,用一个虚拟的类型来 ...

  5. 学习C++模板,类模板

    当我们使用向量时,会经常使用形如:vector<int> a的式子.这个表达式就是一个类模板实例化的例子,vector是一个类模板,我们给他传递模板参数(见<>里),然后创建一 ...

  6. C++复习:函数模板和类模板

    前言 C++提供了函数模板(function template).所谓函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体指定,用一个虚拟的类型来代表.这个通用函数就称为函数模板.凡是函数体 ...

  7. C++ 函数模板与类模板(使用 Qt 开发编译环境)

    注意:本文中代码均使用 Qt 开发编译环境,如有疑问和建议欢迎随时留言. 模板是 C++ 支持参数化程序设计的工具,通过它可以实现参数多态性.所谓参数多态性,就是将程序所处理的对象的类型参数化,使得一 ...

  8. C++ 模板常见特性(函数模板、类模板)

    背景 C++ 是很强大,有各种特性来提高代码的可重用性,有助于减少开发的代码量和工作量. C++ 提高代码的可重用性主要有两方面: 继承 模板 继承的特性我已在前面篇章写过了,本篇主要是说明「模板」的 ...

  9. C++进阶-1-模板基础(函数模板、类模板)

    C++进阶 模板 1.1 函数模板 1 #include<iostream> 2 using namespace std; 3 4 // 模板 5 6 // 模板的简单实例 7 // 要求 ...

  10. IDEA自定义liveTemplates(方法模板、类模板)

    IDEA自定义liveTemplates(方法模板.类模板) 前言,搞这个模板有何意义? 降低大家写方法注释的成本,统一风格.有时候不是开发同学不爱写注释,而是没有合适的载体和空间. IDEA模板设置 ...

随机推荐

  1. Java 删除ArrayList中重复元素,保持顺序

    // 删除ArrayList中重复元素,保持顺序          public static List<Map<String, Object>> removeDuplicat ...

  2. react native 左边固定,右边横向滑动左右自适应高度

    要实现的效果 https://zuobaiquan.github.io/blogImg/201903/01.gif

  3. Python之file

    读写文件 代码: #读写文件str = """i love China!!i hope everyone save"""#打开并书写文件f ...

  4. Javascript介绍(了解)

    Web前端有三层: HTML:从语义的角度,描述页面结构 CSS:从审美的角度,描述样式(美化页面) JavaScript:从交互的角度,描述行为(提升用户体验) JavaScript的历史 1992 ...

  5. python __call__或者说func()()的理解

    __call__ 对象后面加括号,触发执行. 注:构造方法的执行是由创建对象触发的,即:对象 = 类名() :而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()() ...

  6. 静态网站创建工具Docusaurus

    地址:https://docusaurus.io/docs/zh-CN/installation 安装 Docusaurus

  7. 微信小程序button组件样式

    点击微信按键组件才能出授权,所以自定义样式就是必须的了,来自网友的帮助,如下图 <button class='btn1' open-type='contact'> <image cl ...

  8. 12C数据库ORA-40365: The SYS user cannot be locked while the password file is in its current format

    [环境介绍] 系统环境:Solaris + Oracle 12CR2   [背景描述] 基于集团数据库安全检查项,需要把sys用户锁定或者修改复杂口令整改. 在整改前已经对参数remote_login ...

  9. WebGL教程

    https://www.w3cschool.cn/webgl/rleo1oh7.html

  10. 如何参与flink开源项目

    参与flink开源项目 https://flink.apache.org/how-to-contribute.html 1.回答社区问题 2.撰写bug报告 3.对于改进建议或新的特征 4.帮助别人并 ...