C++面向对象编程 (15)

显式实例化:当显式实例化模板时,在使用模板之前,编译器根据显式实例化指定的类型生成模板实例。如前面显示实例化(explicit instantiation)模板函数和模板类。其格式为:template typename function(argulist);template class classname;显式实例化只需声明,不需要重新定义。编译器根据模板实现实例声明和实例定义。

显示具体化:显示具体化,指定模板函数中类型,意思是不要使用swap模板来生成函数定义,而是要使用专门为job类型显示定义的函数定义。因为job是一个结构体,所以swap不可能是直接的利用临时变量做赋值,因此需要在这个函数中重新定义swap的方法,在调用的时候需要使用显示具体化,不要用swap模板来生成函数定义,而是使用我们自己写的方法。
tempalte <> void swap(job &m1,job &m2);

... template<typename T> void Swap(T &,T &);//模版原型 template <> void Swap<job>(job &,job &);//显式具体化 int main(int argc, char const *argv[]) { short a,b; Swap(a,b);//short型隐式模版实例化 job n,m; Swap(n,m);//使用job型显式具体化 template void Swap<char>(char &,char &);//char型显式实例化 char g,h; Swap(g,h);//使用char型显示模版实例化 return 0; } 类模版-一般类模版

与函数相似,类也可以被一种或多种类型参数化。容器类就是一个具有这种特性的典型例子,它通常被用于管理某种特定类型的元素。只要使用类模板,你就可以实现容器类,而不需要确定容器中元素的类型。

在没有类模版之前,可以使用typedef进行通用型的实现,然而,这种方法有两个缺点:首先,每次修改类型时都需要编辑头文件;其次,在每个程序中只能使用这种技术生成一种栈,即不能让typedef同时代表两种不同的类型,因此不能使用这种方法在同一个程序中同时定义int栈和string栈。如:

typedef unsigned long Item; class Stack { private: enum{MAX=10}; Item items[MAX]; int top; public: ... };

现在C++支持模版使用模版类。

模版也是代码重用的一种方式。
类模板,可以定义相同的操作,拥有不同数据类型的成员属性。

类模版是一种泛型编程/元编程方法,其目的是用来生成数据类型的。
由于模板不是函数,它们不能单独编译。模板必须与特定的模板实例化请求一起使用。为此,最简单的方法是将所有模板信息放在一个头文件中,并在要使用这些模板的文件中包含该头文件。

仅在程序包含模板并不能生成模板类,而必须请求实例化。为此,需要声明一个类型为模板类的对象,方法是使用所需的具体类型替换泛型名。
通常使用template来声明。告诉编译器,碰到T不要报错,表示一种泛型.typename代表类型。
main.cpp

#include <iostream> using namespace std; template <typename T> class Complex{ public: //构造函数 Complex(T a, T b):m_a(a),m_b(b) { } //运算符重载 Complex<T> operator+(Complex &c) { Complex<T> tmp(this->a+c.a, this->b+c.b); return tmp; } T get_a() { return m_a; } private: T m_a; T m_b; }; int main() { //对象的定义,必须声明模板类型,因为要分配内容 Complex<int> a(10,20); Complex<int> b(20,30); Complex<int> c = a + b; cout<<c.get_a()<<endl; return 0; } 30 类模版-表达式参数 template <typename T,int n> class ArrayTP { ... }

关键字class(或在这种上下文中等价的关键字typename)指出T为类型参数,int指出n的类型为int。这种参数(指定特殊的类型而不是用作泛型名)称为非类型(non-type)或表达式(expression)参数。假设有下面的声明:

ArrayTP<double,12>

这将导致编译器定义名为ArrayTP<double, 12>的类,并创建一个类型为ArrayTP<double, 12>的eggweight对象。定义类时,编译器将使用double替换T,使用12替换n。

表达式参数有一些限制。表达式参数可以是整型、枚举、引用或指针。因此,double m是不合法的,但double * rm和double * pm是合法的。另外,模板代码不能修改参数的值,也不能使用参数的地址。所以,在ArrayTP模板中不能使用诸如n++和&n等表达式。另外,实例化模板时,用作表达式参数的值必须是常量表达式。

这种方式的优点是执行速度快,缺点是会生成多个副本,因为每种类型都生成一个副本。而使用构造函数的方法将只生成一个副本:

Stack<double>(12);

另一个区别是,构造函数方法更通用,这是因为数组大小是作为类成员(而不是硬编码)存储在定义中的。这样可以将一种尺寸的数组赋给另一种尺寸的数组,也可以创建允许数组大小可变的类。

类模版-部分具体化

C++还允许部分具体化(partial specialization),即部分限制模板的通用性。

template <typename T1> class Pair<T1,int> { }; 类模版-成员模板

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zzjdxx.html