第9章 模板
【考点一】 函数模板
1.函数模板的概念、定义与应用函数模板是一系列相关函数的模型或样板,这些函数的源代码形式相同,只是所针对的数据类型不同。对于函数模板,数据类型本身成了它的参数,因而是一种参数化类型的函数。声明一个函数模板的格式是:template模板形参表声明函数声明
其中的模板形参表声明是由一个或多个模板形参组成(如果是多个,需要用逗号隔开)。每个模板形参具有下面几种形式:(1)typename参数名(2)class参数名(3)类型修饰参数名
这里的参数名可以是任意的标识符。在这三种形式中,前两种是等价的:在声明模板参数时,关键字typename与class可以互换。用typename或class声明的参数称为虚拟类型参数;而用类型修饰声明的参数则挑为常规参数,在形式上与普通的函数参数声明相同。格式中的函数声明与一般函数的声明类似,只是某些类型修饰符被虚拟类型参数所替代。
2.模板实参的省略在调用一个模板函数时,编译系统需要足够的信息来判别每个虚拟类型参数所对应的实际类型,可以从两个不同的渠道获得这样的信息:从模板实参表(用和括起来的参数表)或从模板函数实参表(用(和)括起来的参数表),模板实参的信息优先于函数实参的信息。如果从后者获得的信息已经能够判定其中部分或全部虚拟类型参数所对应的实际参数,而且它们又正好是参数表中最后的若干参数,则模板实参表中的那几个参数可以省略。如果模板实参表中的实参都被省略了,则连空表也可以不要。因此,若x和y都是unsigned型,则addTounsigned(x,y,9)、addT (x、y、9)和addTo(x,y,9)三者是等价的。反之,对于某个模板实参,如果从模板函数的实参表中无法获得同样的信息,就不能省略;或者虽然能够获得同样的信息,但在它后面还有其他不能省略的实参,则其自身还是不能省略。下面列举几种模板实参不能省略的情况。(1)从模板函数实参表获得的信息矛盾。(2)需要获得特定类型的返回值,而不管参数的类型如何。(3)虚拟类型参数没有出现在模板函数的形参表中。(4)函数模板含有常规形参。
3.函数模板的定制对不同的数据类型在处理形式上的统一性是建立模板的基础。但是,这种统一性是相对的,个别数据类型有可能比较特殊,在处理形式上与大多数数据类型不一致。针对这样的特殊情况,可以通过重载模板函数进行定制。这样把重载的模板称为补充模板,相应地,原模板则称为主模板。
【考点二】
类模板
1.类模板的概念、定义与应用类模板就是一系列相关类的模型或样板,这些类的成员组成相同,成员函数的源代码形式相同,所不同的只是所针对的类型(成员的类型以及成员函数的参数和返回值的类型)。对于类模板,数据类型本身成了它的参数,因而是一种参数化类型的类,是类的生成器。类模板中声明的类称为模板类。声明一个类模板的格式是:template模板形参表声明类声明模板形参表声明是由一个或多个模板形参组成;与一般的类声明的不同之处在于,这里的类声明要用模板形参表声明中声明的虚拟类型参数来修饰它的某些成员,使模板类独立于任何具体的数据类型。在模板外对成员函数的声明格式是:template模板形参表声明返回类型类名模板形参表::函数名(函数形参表)函数体其中模板形参表就是由模板形参表声明中声明的参数名组成的序列。应注意,类模板的成员函数都是模板函数,因此在模板外声明成员函数的格式与声明普通模板函数十分相似。用类模板定义对象的格式是:类名模板实参表对象名;或类名模板实参表对象名(构造函数实参表);在定义对象的过程中,编译系统会自动地根据需要生成相应的类定义,这种依据类模板生成类定义的过程称为类模板的实例化。类模板实例所生成的每一个类定义就是相应类模板的一个实例。在用类模板定义对象时,由于没有像函数实参表这样的额外信息渠道,因此无法按函数模板的方式省略模板实参。但是,可以为类模板的参数设置默认值。具体地说,在定义类模板时,可以为模板形参表声明的最后若干个参数设置默认值;而这些有默认值的参数中,最后的若干个对应实参可以在定义对象时省略。
3类模板的派生与继承一谈到继承总涉及到两个类:基类和派生类,它们中任何一个都有可能是模板类,或模板类的实例。下面列出常见的几种情况。(1)普通类继承类模板的一个实例。可以通过继承类模板的一个实例来声明一个类。(2)模板类继承普通类。在声明一个类模板时,应尽可能将类模板中与虚拟类型参数无关的成员剥离出来,构成一个普通类,作为类模板的基类。因此,类模板继承普通类的情况是十分常见的。(3)模板类继承模板类。可以通过继承一个模板类来声明一个类模板。(4)模板类继承模板参数给出的基类。模板的派生甚至可以继承一个未知的基类。也就是说,继承哪个基类由模板参数决定。
【考点一】 函数模板
1.函数模板的概念、定义与应用函数模板是一系列相关函数的模型或样板,这些函数的源代码形式相同,只是所针对的数据类型不同。对于函数模板,数据类型本身成了它的参数,因而是一种参数化类型的函数。声明一个函数模板的格式是:template模板形参表声明函数声明
其中的模板形参表声明是由一个或多个模板形参组成(如果是多个,需要用逗号隔开)。每个模板形参具有下面几种形式:(1)typename参数名(2)class参数名(3)类型修饰参数名
这里的参数名可以是任意的标识符。在这三种形式中,前两种是等价的:在声明模板参数时,关键字typename与class可以互换。用typename或class声明的参数称为虚拟类型参数;而用类型修饰声明的参数则挑为常规参数,在形式上与普通的函数参数声明相同。格式中的函数声明与一般函数的声明类似,只是某些类型修饰符被虚拟类型参数所替代。
2.模板实参的省略在调用一个模板函数时,编译系统需要足够的信息来判别每个虚拟类型参数所对应的实际类型,可以从两个不同的渠道获得这样的信息:从模板实参表(用和括起来的参数表)或从模板函数实参表(用(和)括起来的参数表),模板实参的信息优先于函数实参的信息。如果从后者获得的信息已经能够判定其中部分或全部虚拟类型参数所对应的实际参数,而且它们又正好是参数表中最后的若干参数,则模板实参表中的那几个参数可以省略。如果模板实参表中的实参都被省略了,则连空表也可以不要。因此,若x和y都是unsigned型,则addTounsigned(x,y,9)、addT (x、y、9)和addTo(x,y,9)三者是等价的。反之,对于某个模板实参,如果从模板函数的实参表中无法获得同样的信息,就不能省略;或者虽然能够获得同样的信息,但在它后面还有其他不能省略的实参,则其自身还是不能省略。下面列举几种模板实参不能省略的情况。(1)从模板函数实参表获得的信息矛盾。(2)需要获得特定类型的返回值,而不管参数的类型如何。(3)虚拟类型参数没有出现在模板函数的形参表中。(4)函数模板含有常规形参。
3.函数模板的定制对不同的数据类型在处理形式上的统一性是建立模板的基础。但是,这种统一性是相对的,个别数据类型有可能比较特殊,在处理形式上与大多数数据类型不一致。针对这样的特殊情况,可以通过重载模板函数进行定制。这样把重载的模板称为补充模板,相应地,原模板则称为主模板。
【考点二】
类模板
1.类模板的概念、定义与应用类模板就是一系列相关类的模型或样板,这些类的成员组成相同,成员函数的源代码形式相同,所不同的只是所针对的类型(成员的类型以及成员函数的参数和返回值的类型)。对于类模板,数据类型本身成了它的参数,因而是一种参数化类型的类,是类的生成器。类模板中声明的类称为模板类。声明一个类模板的格式是:template模板形参表声明类声明模板形参表声明是由一个或多个模板形参组成;与一般的类声明的不同之处在于,这里的类声明要用模板形参表声明中声明的虚拟类型参数来修饰它的某些成员,使模板类独立于任何具体的数据类型。在模板外对成员函数的声明格式是:template模板形参表声明返回类型类名模板形参表::函数名(函数形参表)函数体其中模板形参表就是由模板形参表声明中声明的参数名组成的序列。应注意,类模板的成员函数都是模板函数,因此在模板外声明成员函数的格式与声明普通模板函数十分相似。用类模板定义对象的格式是:类名模板实参表对象名;或类名模板实参表对象名(构造函数实参表);在定义对象的过程中,编译系统会自动地根据需要生成相应的类定义,这种依据类模板生成类定义的过程称为类模板的实例化。类模板实例所生成的每一个类定义就是相应类模板的一个实例。在用类模板定义对象时,由于没有像函数实参表这样的额外信息渠道,因此无法按函数模板的方式省略模板实参。但是,可以为类模板的参数设置默认值。具体地说,在定义类模板时,可以为模板形参表声明的最后若干个参数设置默认值;而这些有默认值的参数中,最后的若干个对应实参可以在定义对象时省略。
3类模板的派生与继承一谈到继承总涉及到两个类:基类和派生类,它们中任何一个都有可能是模板类,或模板类的实例。下面列出常见的几种情况。(1)普通类继承类模板的一个实例。可以通过继承类模板的一个实例来声明一个类。(2)模板类继承普通类。在声明一个类模板时,应尽可能将类模板中与虚拟类型参数无关的成员剥离出来,构成一个普通类,作为类模板的基类。因此,类模板继承普通类的情况是十分常见的。(3)模板类继承模板类。可以通过继承一个模板类来声明一个类模板。(4)模板类继承模板参数给出的基类。模板的派生甚至可以继承一个未知的基类。也就是说,继承哪个基类由模板参数决定。