C++—模板(2)类模板与其特化

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

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(0)
17 , _capacity(10)
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 = 10> //带缺省模板参数
 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(0)
15 {}
16 void Test()
17 {
18 SeqList<int> s1;
19 SeqList<int , 20> 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-3;
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-6;
34     }
35 };
36 int main(void)
37 {
38     Compare<int> comp1;
39     std::cout <<comp1.IsEqual(3, 4) <<std::endl;
40     std::cout <<comp1.IsEqual(3, 3) <<std::endl;
41
42     Compare<float> comp2;
43     std::cout <<comp2.IsEqual(3.14, 4.14) <<std::endl;
44     std::cout <<comp2.IsEqual(3, 3) <<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 0;
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(0)
16 , _capacity(10)
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(0)
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(2) ;
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(1, 2) ;
43 }

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

关于特化的总结:

特化的分类

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

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

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

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

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

  1. 模板函数只能全特化,没有偏特化(重载)。
  2. 模板类是可以全特化和偏特化的。

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

模板总结

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

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

时间: 2024-12-24 05:29:20

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

C++学习之模板 ----函数模板、类模板

本博文主要讨论函数模板与类模板以及其简单应用. 1).作用:函数模板和类模板都可以看做是一种代码产生器,往里面放入具体的类型,得到具体化的函数或者class. 2).编译(分为两步): a):实例化之前,先检查模板本身语法是否正确: b):根据 函数调用或者类模板调用 ,先去实例化模板代码,产生具体的函数/类. 也就是说, 没有函数调用或者类类型对象声明,就不会实例化模板代码,在目标文件obj中找不到模板的痕迹. 3):优缺点 模板的缺点是代码膨胀,编译速度慢,而优点是运行速度快. 一.函数模板

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

0.目录 1.函数模板 1.1 函数模板与泛型编程 1.2 多参数函数模板 1.3 函数重载遇上函数模板 2.类模板 2.1 类模板 2.2 多参数类模板与特化 2.3 特化的深度分析 3.小结 1.函数模板 1.1 函数模板与泛型编程 C++中有几种交换变量的方法? 交换变量的方法--定义宏代码块 vs 定义函数: 定义宏代码块 优点:代码复用,适合所有的类型 缺点:编译器不知道宏的存在,缺少类型检查 定义函数 优点:真正的函数调用,编译器对类型进行检查 缺点:根据类型重复定义函数,无法代码复

函数模板与类模板

函数模板,顾名思义,是在生成函数时依照的模板. 有时,我们需要对不同的数据类型做同样的函数操作. 比如:分别对一个int类型数 和 一个double类型数求平方. 这时,虽然都是同样的求平方操作(函数体内代码一样),但是我们必须要编写两个不同的函数,因为处理int类型的函数的参数和返回值类型都应该是int,而处理double类型的函数的参数和返回值都应该是double. 如下:函数体内操作代码一样,设计为重载函数,用相同的函数名,但是参数类型和返回值类型却都不一样,函数需要定义两次. int S

C++笔记(7):泛型编程和模板(函数模板和类模板)

泛型编程和模板 0.泛型编程 1.函数模板 2.类模板 ----------------------------------------------------------------------------------------------------------- 0.泛型编程 所谓泛型就是以独立于任何特定类型的方式编写代码.前面介绍的标准库的容器.迭代器和算法都是泛型编程的具体应用. 模板是泛型编程的基础.使用模板的时候不需要知道模板是如何定义的,但今天我们来介绍如何定义自己的模板类和模

【C/C++学院】0825-类模板/final_override/类模板与普通类的派生类模板虚函数抽象模板类/类模板友元/位运算算法以及类声明/Rtti 实时类型检测/高级new创建/类以及函数包装器

类模板 类模板多个类型默认类型简单数组模板 #pragma once template <class T=int>//类模板可以有一个默认的值 class myArray { public: myArray(); ~myArray(); }; #include "myArray.h" template <class T=int>//每一个函数都需要加上一个默认的值 myArray<T>::myArray() //类模板成员函数在外部,需要加载类型初始

C++模板(类模板、函数模板)

1.在c++Template中很多地方都用到了typename与class这两个关键字,而且好像可以替换,是不是这两个关键字完全一样呢? 答:class用于定义类,在模板引入c++后,最初定义模板的方法为:template<class T>,这里class关键字表明T是一个类型,后来为了避免class在这两个地方的使用可能给人带来混淆,所以引入了typename这个关键字,它的作用同class一样表明后面的符号为一个类型,这样在定义模板的时候就可以使用下面的方式了:      template

类模板,多种类型的类模板,自定义类模板,类模板的默认类型,数组的模板实现,友元和类模板,友元函数,类模板与静态变量,类模板与普通类之间互相继承,类模板作为模板参数,类嵌套,类模板嵌套,类包装器

 1.第一个最简单的类模板案例 #include "mainwindow.h" #include <QApplication> #include <QPushButton> #include <QLabel> template<class T> class run { public: T w; void show() { w.show(); } void settext() { w.setText("A"); }

C++模板学习:函数模板、结构体模板、类模板

C++模板:函数.结构体.类 模板实现 1.前言:(知道有模板这回事的童鞋请忽视) 普通函数.函数重载.模板函数 认识. //学过c的童鞋们一定都写过函数sum吧,当时是这样写的: int sum(int a,int b) { return a+b; } //实现了整数的相加 //如果再想同时实现小数的相加,就再多写个小数的相加.普通实现我就不写了,知道函数重载的童鞋们会这样写: int sum(int a,int b) {//第一个function return a+b;} double su

函数模板和类模板

一.函数模板 函数模板代表一类相同结构的函数,通过用户提供的具体参数,C++编译器在编译时刻能够将函数模板实例化,根据同一个模板创建出不同的具体函数,这些函数之间的不同之处主要在于函数内部一些数据类型的不同. 1 #include "stdafx.h" 2 #include <iostream> 3 using namespace std; 4 5 template <typename T> 6 T max1(T a,T b) 7 { 8 return a>

C++--模板的概念和意义、深入理解函数模板、类模板的概念和意义

一.模板的概念与意义 Q:C++中有几种交换变量的方法?定义宏代码与定义函数A.定义宏代码优点:代码复用,适合所有的类型缺点:编译器不知道宏的存在,缺少类型检查B.定义函数优点:真正的函数调用,编译器对类型进行检查缺点:根据类型重复定义函数,无法代码复用 C.泛型编程--不考虑具体数据类型的编程方式Swap泛型写法中的T不是一个具体的数据类型,而是泛指任意的数据类型C++中的泛型编程函数模板--一种特殊的函数可用不同类型进行调用,看起来和普通函数很相似,区别是类型可被参数化函数模板的语法规则1.