c++ primer plus笔记(10)类模板

一、声明和实现形式:

①声明形式:

template<class Type>   //或template<typename Type>
class classname
{
      ...;
}

这使得classname<type>成为类型的全名。

//置于类首的template<class Type>声明的类型参数Type,同样可以作用于数据成员:

template<class Type>   //或template<typename Type>
class classname
{
private:
      Type a;   //Type类型数据成员a
      ...;
}

②实现形式:

以构造函数实现为例:

template<class Type>
classname<Type>::classname(...)
{
   ...;   //使用与函数模板类似的声明方式
}

成员所属的类成为模板,使得每个成员函数都成为函数模板,导致两个结果:

1>所有函数实现均以template<class Type>起头,并使用classname<Type>::指出其所属的类模板;

2>将原本产生实体代码的函数实现升级为和类声明一样不产生实体代码的编译指令。这意味着类模板的函数实现可以和类声明一样写在头文件(.h)中。

//类方法在其声明处不使用template<class Type>类型参数定义,而是在定义处使用。这与函数模板相反。

3>如果模板是嵌套的:

template<class Type1>
class classname1
{
private:
      template<class Type2>
      class classname2
      {
            ...;
      }
      ...;
}

那么在类声明外定义嵌套函数的实现,起头的template也应该嵌套:

template<class Type1>
   template<class Type2>
   void classname2<Type2>::functionname(...)
   {
      ...;   //函数体
   }

③类模板的类型参数与非类型参数:

1>类型参数可与非类型参数混用:

template<class Type, int n>   //或template<typename Type, int n>
class classname
{
      ...;
}

非类型参数只能为int或enum、&或*中的一种。

不可对非类型参数取地址或修改其值。

//非类型参数往往被用作表示容器类的容量:

实现动态容量的容器模板,方法有两种,使用非类型参数表示容量与使用(构造)函数参数表示容量:

vector<type>vi(n)   //使用heap区,其容量n作为构造函数的参数
array<type, n>      //使用stack区,其容量n作为类标记的一部分

二者区别为:array<type, n>非类型参数表示容量,使得容量n成为类标记的一部分,这将导致模板产生不同的类。

                   vector<type>vi(n)构造函数参数表示容量,使得容量n成为类的一个成员,这将导致类产生不同的对象。

//递归的使用的容器模板可以表示二维数组:

array<array<int, 5>, 10>twodee;
int twodee[10][5];   //二者可以互相取代

通过在容器类模板的类型参数部分使用容器类模板,递归的使用模板,以表示多维容器;

对于array模板类,容器的维度顺序与二维数组相反。

2>非类型参数可以声明默认值:

template<class Type, int n = 1>   //n默认为1
class classname
{
      ...;
}

给模板声明处的非类型参数(int、enum、&、*)声明默认值,使用模板产生实例的时候就可以省略非类型参数以使用默认值。

//模板类函数模板的非类型参数(int、enum、&、*)都可以声明默认值。

3>类型参数可以声明默认值:

template<int n, class Type = int>   //Type默认类型为int
class classname
{
      ...;
}

给模板声明处的类型参数Type声明默认值,使用模板产生实例的时候就可以省略类型参数以使用默认类型。

//只有模板类的类型参数Type才可以声明默认值,函数模板的类型参数则不能。

//无论使用哪一种默认参数,默认参数声明位置必须是在末尾。这与函数的默认参数声明规则相同。

④模板作为模板类类型参数的特殊用法:

template<template <typename T>class Thing>   //模板作为类型参数
class classname
{
private:
      Thing<int> s1;
      Thing<double> s2;   //给出参数处填写的模板应当被实例化的形式
public:
      ...;
}

使用只有形式而内容不明确的模板作为类型参数,使得在初始化时使用相应的具体模板类替换该类型参数。相应的,Thing<int>和Thing<double>也被初始化为具体的模板的实例。

如:

classname<vector>(10);   //classname被初始化为使用vector模板的模板类,其中vector<int>,vector<double>替换Thing<int>,Thing<double>

二、模板的实例化和具体化:

①三种基本的具体化方式语法相同于函数模板的实例化和具体化。

1>隐式实例化:默认的隐式的产生实例。

template<class Type, int n>
class classname
{
      ...;
}
classname<int, 1>(...);   //调用构造函数时隐式的产生一个模板的实例类

2>显示实例化:手动的产生实例。

template class classname<int, 1>;   //显式的声明一个实例类

3>显式具体化:显式的特例化。

template<>class classname<int, 1>   //声明一个模板的特例
{
      ...;
}

②部分具体化:对拥有多类型参数的模板类进行某一些参数的具体化。

template<class Type1, class Type2>   //类模板声明
class classname
{
      ...;
}
template<class Type1>
class classname<Type1, int>   //将Type2具体化为int而Type1不具体化的部分具体化
{
      ...;
}

部分具体化产生比模板描述精确度稍高一些的类描述,其产物并不是实例,仍然是模板类。

三、模板类与友元:

①非模板友元:非函数模板作为友元。

1>参数不使用模板类提供的类型参数:

template<class Type>
class classname
{
      ...;
public:
      ...;
      friend void f_funct();   //友元函数不是函数模板
}

此时提供的友元是所有实例的友元,是已被具体化且不受类型参数影响的友元函数。

//因为已经是具体的函数声明,编译时产生实体代码,所以其实现必须写在实现文件中。

2>参数使用模板类提供的类型参数:

template<class Type>
class classname
{
      ...;
public:
      ...;
      friend void f_funct(classname<Type>&);   //友元函数不是函数模板,但使用了模板类提供的类型参数
}

此时提供的友元按照模板类的具体化被具体化为相应实例的友元,且受类型参数的影响。

②约束模板友元:受到模板类类型参数约束的函数模板作为友元。

template<class Type>
class classname
{
      ...;
public:
      ...;
      friend void f_funct<Type>();   //友元函数是函数模板,使用模板类提供的类型参数
}

此时提供的友元按照模板类的具体化被具体化为相应实例的友元,且受类型参数的影响。

③非约束模板友元:

template<class T> void f_funct();
template<class Type>
class classname
{
      ...;
public:
      ...;
      friend void f_funct<T>();   //友元函数是函数模板,使用独立的类型参数
}

此时提供的友元按照模板类的具体化被具体化为相应实例的友元,且不受类型参数的影响。

四、类模板别名语法:

模板类的名称有时相当冗长,使用别名语法使得其简化:

template<typename T>
using NAME = TEMPLATENAME;   //using 别名 = 模板原型

模板别名语法还可用于函数模板和普通类型,如:

using arrtype = std::array<T, 12>   //类模板别名
using func = void(...)(T, T);   //函数模板别名
using pa2 = const int* (*)[10];   //类型的别名
//只有C++11才支持=别名语法。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值