C++类模板与STL编程

C++类模板与STL编程

1,学习目标

1.理解类模板的概念;
2.掌握类模板的定义、实例化过程,会运用类模板;
3.掌握栈类模板、链表类模板的使用;
4.理解STL编程的基本思想;
5.掌握STL容器的使用;
6.熟练使用STL算法;
7.理解STL函数对象;
  1. 类模板

模板是C++语言的重要特征,它能够显著提高编程效率。利用C++的函数模板和类模板,能够快速建立具有类型安全的类库集合和函数集合,进行大规模软件开发,并提高软件的通用性和灵活性。C++的标准模板库(standard template library,简称STL)编程完全依赖模板的实现。
  
       类模板是能根据不同参数建立不同类型成员的类。类模板中的数据成员、成员函数的参数、成员函数的返回值可以取不同类型,在实例化成对象时,根据传入的参数类型,实例化成具体类型的对象。类模板也称模板类。
 
类模板定义的语法为:
template <模板参数表>
class 类名
{
        成员名;
};
 
   其中:
Ø template为模板关键字。
Ø 模板参数表中的类型为参数化(parameterized)类型,也称可变类型,类型名为class (或typename);模板参数表中的类型也可包含普通类型,普通类型的参数用来为类的成员提供初值。
Ø 类模板中的成员函数可以是函数模板,也可以是普通函数。
       例如,下面定义了一个模板类Student,为了增强类的适用性,将学号设计成参数化类型,它可以实例化成字符串、整型等;将成绩设计成参数化类型,它可以实例化成整型、浮点型、字符型(用来表示等级分)等;
 
template <class TNO, class TScore, int num>  // TNO,TScore 为参数化类型
class Student                     
{
  private:
        TNO StudentID[num];      //参数化类型数组,存储姓名
        TScore score[num];      //参数化类型数组,存储分数
  public:
  TNO TopStudent()     //普通函数
  {
          return StudentID[0];
  }  
  int BelowNum(TScore  ascore) //函数模板
  {
               return 0;
  }
  void sort()                  //普通函数
  {
  }
};
 
模板类的成员函数还可以在类外定义,其语法如下::
template <模板参数表>
类型   类名   <模板参数名表>∷函数名(参数表)
{
        函数体;
}
 
其中:
Ø模板参数表与类模板的模板参数表相同。
Ø模板参数名表列出的是模板参数表中参数名,顺序与模板参数表中的顺序一致。
模板类Student的成员函数在类外实现如下:
template <class TNO, class TScore, int num>
class Student                     
{
  private:
      TNO StudentID[num];
               TScore score[num];
  public:
      TNO TopStudent();
      int BelowNum(TScore ascore);
      void sort();
};
template <class TNO, class TScore, int num>
int Student<TNO, TScore, num>::BelowNum(TScore ascore)
{
   return 0;
}
template <class TNO, class TScore, int num>
void Student<TNO, TScore, num>::sort()
{
}
template <class TNO, class TScore, int num>
TNO Student<TNO, TScore, num>::TopStudent()
{
         return StudentID[0];
}

   一个类模板是具体类的抽象,在使用类模板建立对象时,才根据给定的模板参数值实例化(专门化)成具体的类,然后由类建立对象。与函数模板不同,类模板实例化只能采用显式方式。
       类模板实例化、建立对象的语法如下:
 
   一个类模板是具体类的抽象,在使用类模板建立对象时,才根据给定的模板参数值实例化(专门化)成具体的类,然后由类建立对象。与函数模板不同,类模板实例化只能采用显式方式。
       类模板实例化、建立对象的语法如下:
 
类模板名 <模板参数值表> 对象1, 对象2, …, 对象n;
 
    其中:
Ø 模板参数值表的值为类型名,类型名可以是基本数据类型名,也可以是构造数
    据类型名,还可以是类类型名。
Ø模板参数值表的值还可以是常数表达式,以初始化模板参数表中普通参数。
Ø模板参数值表的值按一一对应的顺序实例化类模板的模板参数表。
 
class String {
  public:
char Str[20];
};
void main()
{
   Student<String, float ,100> S1;
   S1.sort();
   Student<long, int, 50> S2;
   S2.TopStudent();
}
 
class Student                     
{
  private:
        String StudentID[100];
  float score[100];
  public:
  String TopStudent();
  int BelowNum(float ascore);
  void sort();
};
 
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// p10_2.cpp *  单向链表的类模板 *
#include <iostream>
using namespace std;
template <class TYPE>
class ListNode
{
 private:
      TYPE data;
      ListNode * next;
     static ListNode    * urNode;
     static ListNode    * head;
public:
ListNode()//构造函数
{
    next=NULL;
    head=CurNode=this;
}
ListNode(TYPE NewData)
{//拷贝构造函数
    data=NewData;
    next=NULL;
}

2,STL编程

       STL(Standard Template Library),即标准模板库,是一个高效的C++程序库。STL是ANSI/ISO C++标准函数库的一个子集,它提供了大量可扩展的类模板,包含了诸多在计算机科学领域里所常用的基本数据结构和基本算法,类似于Microsoft Visual C++中的MFC(Microsoft Foundation Class Library)。
       从逻辑结构和存储结构来看,基本数据结构的数量是有限的。对于其中的数据结构,用户可能需要反复的编写一些类似的的代码,只是为了适应不同数据的类型变化而在细节上有所出入。如果能够将这些经典的数据结构,采用类型参数的形式,设计为通用的类模板和函数模板的形式,允许用户重复利用已有的数据结构构造自己特定类型下的、符合实际需要的数据结构,无疑将简化程序开发,提高软件的开发效率,这就是STL编程的基本设计思想。
 
逻辑层次来看,STL中体现了泛型化程序设计(generic programming)的思想,它提倡使用现有的模板程序代码开发应用程序,是一种代码的重用技术(reusability)。代码重用可以提高软件开发人员的劳动生产率和目标系统质量,是软件工程追求的重要目标。许多程序设计语言通过提供标准库来实现代码重用的机制。STL是一个通用组件库, 它的目标是将常用的数据结构和算法标准化、通用化,这样用户可以直接套用而不用重复开发它们,从而提高程序设计的效率。
       从实现层次看,STL是一种类型参数化(type parameterized)的程序设计方法,是一个基于模板的标准类库,称之为容器类。每种容器都是一种已经建立完成的标准数据结构。在容器中,放入任何类型的数据,很容易建立一个存储该类型(或类)的数据结构。
       STL主要由五个部分组成,分别是容器(container)、迭代器(iterator)、适配器(adaptor)、算法(algorithm)以及函数对象(function object)。
 
在STL程序设计中,容器(container)就是通用的数据结构。容器用来承载不同类型的数据对象,就如同现实生活中,人们使用容器用来装载各种物品一样,但C++中的容器还存在一定的“数据加工能力”,它如同一个对数据对象进行加工的模具,可以把不同类型的数据放到这个模具中进行加工处理,形成具有一定共同特性的数据结构。例如将int型、char型或者float型放到队列容器中,就分别生成int队列、char型队列或者float型队列,它们都是队列,具有队列的基本特性,但是具体数据类型是不一样的。
       STL容器主要包括向量(vector)、列表(list)、队列(deque)、集合(set/ multiset)和映射(map/multimap)等。STL用模板实现了这些最常用的数据结构,并以算法的形式提供了对这些容器类的基本操作。
       STL中的所有容器都是类模板,是一个已经建立完成的抽象的数据结构,因此可以使用这些容器来存储任何类型的数据,甚至是自己定义的类,而无需自己再定义数据结构。例如利用deque容器,就很容易建立一个队列。
1,顺序容器
容器类名
特性
何时使用
头文件
vector
(向量)
在内存中占有一块连续的空间,存储一个元素序列。可以看作一个可自动扩充的动态数组,而且提供越界检查。可用[]运算符直接存取数据。
需要快速查找,不在意插入/删除的速度快慢。能使用数组的地方都能使用向量。
<vector>
list
(列表)
双向链接列表,每个节点包含一个元素。列表中的每个元素均有指针指向前一个元素和下一个元素。
需要快速的插入/删除,不在意查找的速度慢,就可以使用列表。
< list >
deque
(双端队列)
在内存中不占有一块连续的空间,介于向量和列表之间,更接近向量,适用于由两端存取数据。可用[]运算符直接存取数据。
可以提供快速的元素存取。在序列中插入/删的速度除较慢。一般不需要使用双端队列,可以转而使用vector或list。
< deque >
容器类名
特性
何时使用
头文件
set
(集合)/
multiset
(多集)
set是一个元素集合。集合中的元素按有序的方式存储。set中没有重复的元素,但multiset中允许有重复的元素。
需要使用元素集合,而且对元素的查找、插入和删除操作都较为频繁时,就可以使用set/multiset。
<set>
map
(映射)/
multimap
(多映射)
map是{键(key),值}对的组成的集合。集合中的元素按键排列。multimap是允许键/值对有重复的集合。map和multimap的关系如同set和multiset之间的关系
如果希望将键/与值相关联就可以使用map/muitimap。
< map >
3,STL算法 
       算法(algorithm)就是一些常用的数据处理方法,如向容器中插入、删除容器中的元素、查找容器中的元素、对容器中的元素排序、复制容易中的元素等等,这些数据处理方法是以函数模板的形式实现的实现的。        算法之美就在于它们不仅独立于底层元素的类型,而且也独立于所操作的容器,利用这些已经定义的算法和迭代器,程序设计人员可以方便灵活地地存取容器中存储的各种数据元素。         在STL中,算法的“神奇之处”在于:算法并非容器的一部分,而是工作在迭代器基础之上,通过迭代器这个“中间人”存取容器中的元素,算法并没有和特定的容器进行绑定。        在传统的软件开发方法中,算法与数据类型、数据结构紧密耦合,缺乏通用性。而STL 倡导泛型编程风格,即以通用的方式来编写程序。STL采用C++模板机制实现了算法与数据类型的无关性。实际上,为了支持通用程序设计,STL实现了算法与容器(数据结构)的分离。这样,同一算法适用于不同的容器和数据类型,成为通用性算法,可以最大限度地节省源代码。因此STL比传统的函数库或类库具有更好的代码重用性
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/*******************************************
*        程序名:p10_9.cpp                    *
*  功  能:算法(algorithm)示例        *
*******************************************/
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
template<class T>
void print(T &con)    //输出容器中所有元素
{
  if(con.empty())
         cout<<"Container is empty!"<<endl;
  else
  {
  T::iterator it;   //设置迭代器
  for(it=con.begin(); it!=con.end();it++)
  {
cout<<*it<<" ";
      }
  cout<<endl;
  }
}

26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
int main()
{
  int num;
  vector<char> vec_A(8);  //定义容器vec_A
  cout<<"Fill vec_A with 'A':"<<endl;
  fill(vec_A.begin(),vec_A.end(),'A');  //填充数据元素
  print(vec_A);
  cout<<"Copy element of vector to vec_A:"<<endl;
  char array_B[]={'B','B','B','B',};
  vector<char> vec_B(array_B,array_B+4);  //定义容器vec_A,并初始化
  copy(vec_B.begin(),vec_B.end(),vec_A.begin()+2);   //复制数据元素
  print(vec_A);
  cout<<"Remove 'A' from vec_A:"<<endl;
  vector<char>::iterator it;
  it=remove(vec_A.begin(),vec_A.end(),'A');  //移除数据元素
  vec_A.erase(it,vec_A.end());               //删除数据元素
  print(vec_A);
  cout<<"Repalce 'B' with 'C':"<<endl;
  replace(vec_A.begin(),vec_A.begin()+2,'B','C');  //替换数据元素
  replace(vec_B.begin(),vec_B.end(),'B','X');
  print(vec_A);

52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
  cout<<"Inserting:"<<endl;
  vec_A.insert(vec_A.begin(),'D');  //插入数据元素
  vec_A.insert(vec_A.end(),'A');
  print(vec_A);
  cout<<"Sorting:"<<endl;
  sort(vec_A.begin(),vec_A.end());  //排序
  print(vec_A);
 
  vector<char> vec_C(vec_A.size()+vec_B.size());
  cout<<"Merge vec_A and vec_B:"<<endl;
  merge(vec_A.begin(),vec_A.end(),vec_B.begin(),vec_B.end(),
  vec_C.begin());  //合并
  print(vec_C);
  num=count(vec_C.begin(),vec_C.end(),'B');  //统计数据元素
  cout<<"Counting the number of 'B' in vec_C:"<<endl;
  cout<<num<<endl;
  return 0;
}

类模板是能根据不同参数建立不同类型对象的类,类模板中的数据成员、成员
   函数的参数、成员函数的返回值可以取参数化类型。
类模板实例化是在建立对象时,根据传入的参数类型,将类模板实例化成具
   体类,然后再建立对象。
栈是一种先进后出FILO(First In Last Out)的一种结构,在程序设计中广
   泛使用栈,将栈设计成一个类模板,就可以在栈中存放任意类型的数据。
动态链表的插入与删除节点的性能优于静态数组,在程序设计中广泛使用链
   表,将链表设计成一个类模板,就可以在链表节点中存放任意类型的数据。
STL(Standard Template Library)是C++提供的标准模板库,它可以实现高
   效的泛型程序设计。
STL容器包括顺序容器和关联容器,利用容器适配器可以将顺序容器转换为新
   的容器。
在STL中,算法独立于所操作的容器,利用已经定义的算法和迭代器,用户可
   以方便灵活地地存取容器中存储的各种数据元素。
在STL中,函数对象是由模板类产生的对象,函数对象在STL中被广泛用作算
   法中子操作的参数,使算法变得更加通用。
  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值