看看头条
当前位置:看看头条 > 历史 > 正文

C++|泛型编程与半成品的模板、标准模板类库STL

C和C++都是强类型语言,定义函数时,函数前面是需要声明数据类型的,这样就会出现一个问题,如定义一个简单的功能相同的加法函数,是不是需要为每种数据类型分别定义一个,然后再分别调用呢?

通过类和模板的封装,可以部分地解决这个问题。

class calc

{

int add(int m, int n)

retunr m+n;

}

float add(float i, float j)

return i+j;

}

……

}

这样的类产生以后,用calc.add方法时,就不用考虑这两个参数的具体数据类型了。

人们设想有这样的一种编程机制,让一个函数适应所有的数据类型,包括自己定义的数据类型。

后来,人们实现了这种机制,能适应所有的数据类型,就称为泛型编程(Generic Programming)。于是现在C++也支持这种编程机制。

泛型编程最初提出的动机很简单直接,就是发明一种语言机制,能够帮助实现:

I 一个通用的标准容器库。所谓通用的标准容器库,就是要能够做到,比如用一个List类存入所有可能类型的对象。

II 泛型编程可以编写完全一般化并可以重复使用的算法、其效率与针对某特定数据类型而设计的算法相同。泛型即是指具有在多种数据类型上皆可操作的含义,这样算法与具体的数据类型完全分离,其中算法是泛型的,不与任何特定数据结构或对象类型联系在一起。

可以用一句话描述泛型编程:把数据类型(包括自定义数据类型)作为一种参数传递进来的机制。

我们需要让程序更智能,C++很需要泛型这种新的编程模式,于是引入了模板这个功能。也就是说,在C++中,引入了关键字template。

模板可以认为是针对一个或多个尚未明确的类型而编写一套函数或类型,这样就可以推迟对某些类型的选择,直到想使用模板或者对模块进行专门化处理时。使用模板,可以让程序员面对相似而又略有不同的特性时,更快捷地编写代码,提高开发效率。

使用模板是为了实现泛型,可以减轻编程的工作量,增加函数的重用性(增加重用性几乎是编程语言的基本思路,函数的引入本身就是为了增加代码的重用性)。

这样就不需要针对不同的类型写很多个功能相同的函数,而使用模板则只使用一个函数即可:

template<class T>

T add(T m, T n)

{

return m + n;

}

调用时可以显示说明类型。例如:add(3,4)。

这样,有了泛型编程思想,有了模板功能,C++程序员们就可以编写出很多通用的针对不同数据类型的算法,其中,STL脱颖而出,成为C++标准,只需掌握这个标准,就不用自己费心费力从头开始写一些算法。这就是所谓开发的基本思想:不要重复发明轮子。

简单说,STL(Standard Template Library),标准模板库,是一个具有高可用性、高效的C++程序库。该库包含了诸多在计算机科学领域里所常用的基本数据结构和基本算法。

泛型编程的代表作品STL是一种高效、泛型、可交互操作的软件组件。STL包含各种泛型算法(algorithms)、泛型迭代器(iterators)、泛型容器(containers)以及函数对象(function objects)。STL以容器(containers)和迭代器(iterators)为基础,是一种泛型算法(generic algorithms)库,容器的存在使这些算法有东西可以操作,迭代器提供了一个遍历容器全部元素的指示器。

从根本上说,STL是一些“容器”的集合,这些“容器”有list、vector、set、map等,都是我们熟悉的数据结构。STL也是算法其他一些组件的集合。这里的“容器”和算法的集合是世界上很多聪明人多年的杰作。STL的目标是标准化组件,这样就不用重新开发,可以使用现成的组件。STL被内建在C++的编译系统之内,是C++的一部分,因此不用额外安装,只需在头文件中包括进来即可。

容器是管理序列的类,通过容器类提供的成员函数,实现各种对序列中元素的操作,是一种高度的泛型抽象,部分算法也可以应用于容器序列的控制。

STL提供了各种窗口模板类,通常这些模板类包括:

C++|泛型编程与半成品的模板、标准模板类库STL

容器的使用需要分别包含相应的头文件,因为容器都是类模板,要定义或实现某种特定的容器对象,必须在窗口后加入一对尖括号,括号中提供容器中存放元素的数据类型:

#include <vector>

using namespace std;

a = [1,3,5,7]

vector <int> vec(a);

vector是定义于名称空间(namespace)std内的模板,其定义在头文件<vector>中。

template <class T, class Allocator=allocator<T>> class vector;

vector中的元素可以是任意型别T,必须具备可设置、可复制两个属性。第二个参数用于设置空间配置器,用于定义内存模型,默认是allocator。

vector就像一个动态数组,是典型的“将元素置于动态数组中加以管理”的抽象概念。

一般情况下,算法大致分为:基本算法、数据结构的算法、数论与代数的算法、计算几何算法、图论算法、动态规划及数值分析、加密算法、检索算法、随机化算法、并行算法等一系列算法。

在数据容器内部对数据元素的操作的算法称为数据结构的算法,一般包括增、查、删、改、排序等操作。

STL的算法允许使用者传递自定义的操作(函数),方便由STL算法调用。这些操作(函数)既可以是一般函数,也可以是仿函数。如果返回值是bool类型,称为条件判断式。

关于算法函数设计,有两个主要的通用部分。首先,这些函数都使用模板来提供通用类型;其次,这些函数都使用迭代器来提供访问容器中数据元素的通用表示。

STL中的算法库分为4种:非修改式序列算法、修改式序列算法、排序和相关算法、通用数字算法。

迭代器是连接容器和算法的纽带,是指针概念的抽象,是能够遍历某个序列内的所有元素的对象。通俗地讲,迭代器是一个指示器,迭代器技术能够使程序反复地对STL容器内容进行访问。当参数化类型为C++内部类型时,迭代器是C++的指针。STL定义了5种类型的指示器:输入、输出、前向、双向和随机访问。

单个处理数据效率不高,数组、链表可以批量地处理数据。对于数组、链表这样的组合数据类型,既可以整体操作,也可以对包含的元素进行遍历。对元素的遍历一般通过一个循环去进行。对于数组,只要添加一个辅助的整形数据,如i,一般初始其值为数据的第一个元素的下标0,然后使用增量运算符++即可进行数组元素的遍历了(通过下标操作符)。而对于链表,一般定义一个辅助指针,让其指向链表头指针,同样通过增量运算符++即可遍历链表元素。在STL中,为了完成类型的功能,定义和使用了迭代器的技术。

C++|泛型编程与半成品的模板、标准模板类库STL

……

int a[]={1,3,4,6,8,7};

vector<int> arr(a,a+6);

vector<int> ::iterator begin; //定义迭代器

/*Initialize a vector*/

cout<<“Initialize vector arr with a:”<<endl;

for(begin=arr.begin();begin!=arr.end();begin++)

{cout<<*begin<<” “<<endl;} //使用迭代器

……

迭代器总是指向窗口的某一个元素,这个元素称为当前元素,可以使用增量运算符++指向下一个元素。随机存取迭代器可以通过加减整数,取得相对地址。

开发程序,就像生产一个产品,需要使用基础材料、部件(半成品)、工艺(如果要实现生产的自动化,材料和部件的存储就很重要)。如果所有的部件都是自己用基础材料生产,则生产周期长,效率低,问题也多;但如果有标准部件提供给你,你只需组装就行了,那效率就高了。同时,这些标准件可是经过优化的。开发程序的基础材料就是基本数据类型,完全免费,一些函数库、模板类库就是标准件,也是完全免费。模板类库中封装了数据序列(如数组、链表),也封装了算法(通过迭代器对数据序列元素的操作)。就像标准件封装了基础材料与工艺。

所以STL不仅实现了泛型的功能,还实现了半成品的功能。

-End-

复制转发: C++|泛型编程与半成品的模板、标准模板类库STL

评论 0