第5章 模板 教学PPT_动物昆虫_PPT模板_实用文档
第5章 模板· 函数模板 · 类模板· 派生与模版 · 模板特化? 学习目标1 掌握函数模板和类模板的定义与使用理解类模板之间的 2继承与派生熟练掌握模板的特化3? 函数模板?点击查看本案例相关知识点类模板?点击查看本案例相关知识点派生与模版?点击查看本案例相关知识点模板特化?点击查看本案例相关知识点小结? 模板什么是模版?模板是C++支持参数化多态的软件,它可以推动类型参数化模板函数课件, 即把类别定义为参数,真正推动 了代码的可重用性,减轻了编程 及维护的工作量和难度。模板使类或变量能在编译时定 义所需处理跟返回的数据类型, 一个模板只是一个实实在在的 类或函数,仅仅是一个类或函 数的表述。模板通常分为函数 模板和类模板。? 5.1 函数模板定义一个 函数模板函数模板并不是一个可以直接使用的 函数,它是可以形成多个变量的模板。add()intdoublefloat使用模板的目的就是要让那些程序的谋求与 类型无关。? 5.1 函数模板定义函数模板声明的模语板法的 格式如下所示可:以用class关键字关键字代替template返回值类别 函数名(参数列表){函数体;}函数模板的用法案例代码接下来,通过一个案例来演示,如例5-1所示。
? 5.1 函数模板函数模板的 实例化函数模板并不是一个函数,它只相当于一个 模子,定义一次就能使用不同类型的参数来 调用该方程,这样做可以增加代码的书写, 提高代码的复用性。使用变量模板不会减少最终能执行程序 的大小,因为在调用函数模板时,编译器会 根据读取时的参数类型进行相应的示例化。? 5.1 函数模板什么是实例化所谓实例化,就是用类别参数去替 换模板中的模版参数,生成一个具 体类别的真正函数。实例化可分为 隐式实例化与显式实例化。? 5.1 函数模板1 隐式实例化隐式实例化是依据函数调用时传入的数据类别确定模板类库T的类别,模板类库的 类型是隐式确定的。在例5-1中第一次调用add()函数模板时,传入的是int型数据add(1,2),此时编译 器根据传入的左值推演出模板实参类型是int,就会将方程模板实例化出一个int类 型的变量,如下所示:int add(int t1, int t2) {return t1 + t2; }? 5.1 函数模板编译器生成准确类型变量的这一过程就称为实例化,生成的变量称为模板函数。生成int类型的变量后,再将赋值1和2传入进行运算。同理当传入double类 型的数据时,编译器先将模版实例化为如下形式的变量:double add(double t1, double t2) {return t1 + t2; }每一次调用时就会按照不同的类别案例化出不同类型的函数,所以最后 可执行程序的大小并不会减少,它也是增加了程序员对代码的复用。
? 5.1 函数模板2 显式实例化隐式实例化不能为同一个模板形参指定两种不同的类别。可以用另一种 实例化方式来解决这个难题——显式实例化。显式实例化就是显式的选定函 数模板中的数据类别。其词汇格式如下所示: template 函数返回值类别 函数名(参数列表); 注意这是声明语句,要以分号结束,中是显式实例的数据类别,即应实例 化出一个什么类别的变量,例如,显示实例化为int,则在调用时,不是int类 型的数据会转化为int类型进行推导。 例如将例5-1中的add()函数模板显式实例化为int类型,代码如下所示: template int add(int t1, int t2);? 5.1 函数模板举个反例For example显式实例化案例代码 如例5-2所示多学一招案例代码? 5.1 函数模板函数模板的 重载函数模板可以拿来创建一个通用用途 的变量,以支持多种不同形参,不同 类型的参数调用就形成一系列重载函 数。? 5.1 函数模板如例5-1中两次调用add()函数模板,编译时会按照传入参数不同实例化出两个函 数,如下所示:int add(int t1, int t2) //int类型参数实例化出的变量 {return t1 + t2; } double add(double t1, double t2) //double类型参数实例化出的变量 {return t1 + t2; }函数模板的重载案例代码接下来,通过一个案例来演示,如例5-3所示。
? 5.1 函数模板脚下留心:使用函数模板要留意的疑问脚下留心案例代码? 5.2 类模板定义一个类模板并实例化函数可以定义模板,对于类来说,也可以定义一个类模板,类模板是对于成员 数据类别不同的类的具象,它不是代表一个具体的实际的类,而是一个类型的 类,一个类模板可以生成多种具体的类,定义类模板的格式如下所示: template class 类名 { ……… }? 5.2 类模板类模板中的关键字含 义与变量模板相似。注意类模板的模版形参不能为空,一旦声明了类模 板就可以用类模板的数组名声明类中的成员变 量跟成员函数,即可以在类中使用数据类别的 地方都可以使用模板类库名来声明。template class A { public:T a; T b; T func(T a, T b); };? 5.2 类模板由于类模板包含种类参数,因此也称为参数化 类,如果说类是对象的抽象,对象是类的例子,则 类模板是类的具象,类是类模板的例子。定义了类模板后还要使用类模板创建对象或者实现类中的成员变量,这个 过程虽然只是类模板实例化的过程,实例化出的详细类称为模板类。如果用类模板创建类的对象,如用上述定义的模板类A创建对象,则在类A 后面跟上一个,并在上面说明相应的类别,格式如下所示:A a;? 5.2 类模板这样类A中凡是用到模板类库的地方就会被int类型所代替。
当类模板有两个模 板形参时,创建对象时,类型之间应用逗号分隔开,如定义一个有两个模板形参的 类B,然后用B创建类对象,示例代码如下所示:template class B { public:T1 a; T2 b; T1 func(T1 a, T2& b); }; B b; //创建模板类B的一个对象使用类模板时,必须应为模板形参显式指定数组,不存在实参推演过程, 也就是说不存在将整型值10推演为int类型传递给模板类库,必须应在中指 定int类型,这一点与变量模板不同。? 5.2 类模板类模板案例代码 如例5-4所示?多学一招:模板声明或定义的作用域模板的声明或定义只能在全局、命名空间或类范围内进行,不能在局部范围、 函数内进行,比如不能在main()函数中声明或定义一个模板。声明或定义 一个模板还有下列几点需要留意:1 如果在全局域中声明了与模版参数同名的函数,则该数组被隐藏。 2 模板参数名不能被称作类模板定义中类成员的名字。 3 同一个模板参数名在模板参数表中只能出现一次。 4 在不同的类模板声明或定义中,模板参数名可以被重复使用。? 5.2 类模板在类模板外部定义成员函数类模板的成员变量都是在类的外部实现的,类模板的成员变量可以在类模 板的定义中定义(inline函数),也可以在类模板定义之外定义(此时成员变量定 义前面还要加上template及模板参数),在类模板外部定义成员变量的方式如下 所示: template 函数返回类型 类名::函数名(参数列表){}? 5.2 类模板template是类模板的声明,在实现成员函数时,也应 加上类作用域,而且在类名后应用指明类的模版形参。
例如有以下类模板的定义:template class B { public:T1 a; T2 b; T1 func(T1 a, T2& b); };? 5.2 类模板上述代码中,如果在类模板外定义类B的成员函数func(),其实现如下所示: template T1 B::func(T1 a, T2& b){}类模板外定义类案例代码 如例5-5所示? 5.2 类模板类模板与友元函数声明友元函数 有三种情况1 非模板友元函数 2 约束模板友元函数 3 非约束模板友元函数? 5.2 类模板1.非模板友元函数友元函数案例代码,如例5-6所示? 5.2 类模板1 .非模板友元函数友元函数2 .约束模板友元函数案例代码,如例5-7所示。? 5.2 类模板1.非模板友元函数友元函数2 .约束模板友元函数3 .非约束模板友元函数案例代码,如例5-8所示。? 5.3 派生与模板模板的 参数1 类型参数 2 非类别参数 3 模板类库? 5.3 派生与模版1 类型参数以typename或者class关键字标记的的模版参数就称为类型模板参数(type templateparameter),类型模板参数是类我型们形使参用模板的主要目的。
例如以下模版声明:template T add(T t1, T t2);可以为模板定义多个类别模板参数,也可以为类别模板参数选定默认值,示例代码 如下所示:template class A { public:void func(T, U); };注意:可以为类模板更改默认值,但不能为变量模板 设置默认值。? 5.3 派生与模板2 非类别参数非类型的模模板的非类型参数也就是内置类型板形参形,参例如定义如下模板:template class A {//…… };非类型模板实参相当于为函数模板或类模板预定义一些常量,在生成模板实例时, 也规定需要以常量,即编译期已知的值为非类型模板参数赋值。非类型模板形参只 可以是整型、枚举、指针跟引用类别。? 5.3 派生与模板2 非类别参数非类型模板参数的灵活之 处在于?模板中声明的常量,在模版的所有例子中都带有相似的值,而非类别模板参 数则针对在不同的模板实例中拥有不同的值来满足不同的意愿。? 5.3 派生与模板2 非类别参数比如要定义一个常量数组,如果已知要用到一个大小为10的数组,则可以将 数组长度定义为10,代码如下所示: template class Array {static const unsigned size = 10; T arr[size]; //数组大小为定义好的常量 };案例代码接下来,通过一个案例来演示,如例5-9所示。
? 5.3 派生与模板3 模板形参模板形参,顾名思义就是模板的参数是另一个模板,其声明格式如下所示: template class A> class Class { A a; };模板参数使用的之后与通常参数 没什么差别,不要拘泥于它的语法实 现,只要记住可以使用模板作为模版 的一个参数就能。? 5.3 派生与模板类模板 的派生1 类模板派生普通类 2 类模板派生类模板 3 普通类派生类模板? 5.3 派生与模板类模板 的派生1 类模板派生普通类 2 类模板派生类模板 3 普通类派生类模板? 5.3 派生与模板类模板 的派生1 类模板派生普通类 2 类模板派生类模板 3 普通类派生类模板? 5.3 派生与模板类模板 的派生1 类模板派生普通类 2 类模板派生类模板 3 普通类派生类模板? 5.4 模板特化什么是特化?所谓特化就是将泛型的东西具体化。模板特化就是为已有的模板参数进行一些让其特殊化的指定,使得原本不受任 何约束的模板参数,受到特定约束或完全被指定出来。两种特化形式偏特化全特化? 5.4 模板特化偏特化偏特化就是模板中的模板参数没有被全部确认,需 要编译器在编译时进行确认。
例如定义一个类模板,如下所示: template class A {//…… };将其中一个模板类库特化为int类型,如下所示:template class A {//…… };? 5.4 模板特化全特化全特化就是模板中的模板参数全部被选定为确认的 类型模板函数课件,其标志就是产生出完全确认的东西。例如有类模板定义,如下所示:template class Compare { public:bool IsEqual(const T& lh, const T& rh) {return lh == rh; } };? 5.4 模板特化将其特化为对float类别数据的非常,定义如下所示: template class Compare { public: bool IsEqual(const float& lh, const float& rh) { return abs(lh - rh)