1、模板基本概念及语法
C++提供了多种代码重用机制,在前面介绍派生和继承时,派生类可以继承基类中的成员变量和成员函数。模板是另一种代码重用机制。
有时候在设计程序的时候会遇到这样一种情况:需要设计的几个类,其功能都是一样的,仅仅只是需要操作的数据类型不同。遇到这样的情况,固然可以将所有的类都设计一遍,但是在C++中,我们有更好的方法:设计一个模板类。假设我们需要创建一个数组类,该数组可能是整型数组,也可能是double类型数组、string类型数组等,为此我们需要设计一个数组的模板类。
例1:
在本例中,我们定义了一个数组的模板类array,借用该示例,我们来了解一下模板类的一些基本语法。在本例中我们定义模板类array时,前面加上了一句声明:
template< class T >
该语句称为模板头,可以单独放在一行,也可以与后面的class array同放在一行,这都没有关系。模板头中的“T”我们称之为类参数,类参数表示将会以确定的数据类型替代之,任何有效的C++标识符均可以作为类参数,当然通常我们还是会用“T”来做类参数。
模板头中template关键字和“<”之间可以保留一个空格,但通常这两者之间不留空格。
对于模板类而言,在类外定义类中的成员函数的时候都需要加上模板头。同时由于array是个模板类,因此类名是array< T >,故而在类外定义带参构造函数的完整形式是:
而如果是在类内部定义该函数,则会相对简单一些:
在本例中用到了前面所介绍的很多知识点,例如将默认构造函数置为private属性,重载下标操作符,重载输出操作符等,这些知识点希望能够仔细领会。
模板类至少有一个类参数,但是可以有多个类参数,每一个类参数前都必须有关键字class或者类型名。
例2:
2、模板类实例化
我们可以通过“< >”指定一种数据类型,从而创建出一个模板类的实例。有了前面定义的模板类,如果我们想创建一个int数组可以按照如下方式使用模板类:
array < int >表明用int类型来代替模板类中的类参数“T”,编译器会将模板类array中所有的类参数T都用int来代替。例如类中的私有成员变量“T * num;”会被替换为“int * num;”。对类中的成员函数也会进行相同的替换,如“T & operator[]( int );”将会被替换为“int & operator[]( int );”。
如果我们定义对象:
则模板类中所有的类参数“T”都将被换为double。我们称array < int >和array < double >成为模板类的实例。使用这些实例就与使用普通类是一样的。
例1:
本例是一个完整的模板类示例,在该例中我们定义了一个array模板类,在主函数中我们对其进行了实例化,“array< int > A(10);”实例化之后创建了一个对象A,该对象是一个包含10个元素的整型数组。之后用一个for循环给数组赋初值,由于我们重载了下标操作符,因此可以凭借下标直接访问相应的数组元素。之后直接输出A数组的所有元素,此时调用的是输出操作符重载函数。
我们在例1中创建的对象A是属于模板类实例化后的类的,而不是属于模板类的。换言之模板类不进行实例化就不能创建对象。
例2:
在本例中,三种定义对象的方式都是无效的,模板类不进行实例化是无法创建对象的。
另外模板类可以以参数的形式出现在函数的参数列表中,例如例1中的输出操作符重载函数“template< class T > ostream & operator<<(ostream & out, const array & A)”,该函数的第二参数是array 的引用,如果参数列表中有模板类,则函数前面必须加上模板头,在例1中的模板头为“template< class T >”。
3、模板中的函数式参数
在前面我们已经提到过模板类至少有一个类参数,但是可以有多个参数,这些参数中可以存在非类类型的参数,例如系统内建的普通数据类型参数或程序自定义的数据类型参数,我们将这种非类类型的参数称之为函数式参数。
例1:
在本例中例举了函数式参数的用法,在模板头中,先是一个类参数T,之后是两个函数式参数S和R。
例2:
在本例中,我们将前面的array模板类进行了修改,使之有两个参数,一个是类参数T,另一个是函数式参数S。修改后的array模板类用默认构造函数替代了带参构造函数。因为在模板类中添加了一个函数式参数S以表示数组的大小,因此我们就不需要在定义对象时利用带参构造函数的参数来确定数组的大小。在前面array模板类,我们需要以以下的方式定义对象:
修改后的array,我们只需要按照如下方式定义对象:
修改后的array类的类名变为了array< T, S >。对于修改后的array类,想要将其实例化则必须提供两个参数的实例,例如:
都是可以正确实例化并定义对象的,但是如果只提供一个参数则是不可以的,例如:
这两种情况都是错误的的实例化。
在模板类实例化过程中,我们需要用具体的数据类型来代替类参数,用具体的数值来替换函数式参数,如此才能实例化成功。
4、标准模板库(STL)的概念
STL(Standard Template Library)标准模板库是标准C++库中的一部分,标准模板库为C++提供了完善的数据结构及算法。标准模板库包括三部分:容器、算法和迭代器。容器是对象的集合,STL的容器有:vector、stack、queue、deque、list、set和map等。STL算法是对容器进行处理,比如排序、合并等操作。迭代器则是访问容器的一种机制。
在C++定义数组时,我们必须提前知晓数组的大小,然后为了避免因为新数据的加入而导致越界,因而需要不断地进行越界检测,这样一来效率就大大降低了。而使用STL有一个非常大的优点就是不需要提前知道数组的大小,当有新元素加入时,容器会自动增大,删除元素时,容器会自动减小。
除此之外,STL还提供了大量的算法用于操作容器。STL具有可扩展性,也就是说可以增加新的容器和算法。
STL基本容器可以分为:
1)序列式容器,主要有list、vector、deque
2)关联式容器,主要有set、multiset、map、multimap
序列式容器可以像数组一样通过下标进行访问。关联式容器则是需要通过键值进行访问,关联式容器可以将任何类型的数据作为键值。
网友评论