容器类和模板类\t\r ?
容器类是用来存放多个其它类型的对象的类。string类就是一个容器类,它是用来存放char类型的变量的。对于其它类型,如double、string或新的类型,如Student,我们也可以定义它们的容器类。通常一个容器类只可以存储一个类型的多个对象。模板容器类是可以存放不同类型的对象的类。定义了一个模板容器类,相当于定义了多个容器类,它们分别可以存放不同类型的对象。\t\r ?
1. 容器类Vector\t\r ?
容器类container是用来存放其它类型的对象的类型。下
面我们介绍一个存放double类型变量的容器类。这个容器类封装了一个数组,这个封装提供了一种可变长度的数组,同时免除了用户动态分配内存空间的麻烦。我们先看看它的用法,然后再讲解它的实现。\t\r ?
1 int main() {
2 Vector vector1;
3 for (int i = 0; i < 10; ++ i) { 4 vector1.push_back(i + 0.5); 5 }
6 for (int i = 0; i < vector1.size(); ++ i) { 7 cout << vector1[i] << endl; 8 } 9 }
在第二行,我们定义了一个容器类Vector的对象vector1。
这个时候,容器类对象vector1存放的double变量的个数为0。然后,我们调用对象函数push_back,它向容器容器类对象vector1添加一个double变量。容器类对象vector1中的
double
变量是按顺序存放的,每次调用push_back,容器的大
小(所存放double变量的个数)便增大1,且新增的double变量被放在最后。\t\r ?
当执行到第6行之前,容器类对象vector1中已经有10个double变量,对象函数vector1.size()将返回10。最后,在第7行我们看到,容器类Vector还提供对象操作符函数
operator [],通过它可以获得容器中各个double变量的引用。\t\r ?
容器类Vector的实现细节与类string相似。在这个
Vector类的中elements是存放一个double数组的地址变量,
所存放的double数组是运行时动态分配的。capacity是所分配的double数组的容量(大小)。在我们将要讲解的这个容器类Vector中,我们不浪费存储空间(这不一定是好事),所以实际上存放double变量的个数就是capacity。看下面的程序,如果没有问题,可以跳过这个小节余下的讲解内容。\t\r ?
1 class Vector
2 {
3 private:
4 double * elements; 5 int capacity; 6
7 void copy0(double to[], const double from[], 8 int num) const {
9 for (int i = 0; i < num; ++ i) { 10 to[i] = from[i]; 11 } 12 } 13
14 void ensureCapacity0(int capacity2) {
15 double * temp = new double[capacity2]; 16 copy0(temp, elements, capacity); 17 delete [] elements; 18 elements = temp;
19 capacity = capacity2; 20 } 21
22 void assign0(const Vector & vector2) { 23 if (elements != 0) { 24 delete [] elements; 25 }
26 capacity = vector2.capacity;
27 elements = new double[capacity];
28 copy0(elements, vector2.elements, capacity); 29 } 30 31 public:
32 Vector() {
33 // have to waste one element when empty 34 elements = new double[1]; 35 capacity = 0; 36 } 37
38 ~Vector() {
39 delete [] elements; 40 } 41
42 Vector(const Vector & vector2) { 43 elements = 0;
44 assign0(vector2); 45 } 46
47 Vector & operator = (const Vector & vector2) { 48 assign0(vector2); 49 } 50
51 int size() const { 52 return capacity;
53 } 54
55 void push_back(double elem) {
56 ensureCapacity0(capacity + 1); 57 elements[capacity - 1] = elem; 58 } 59
60 double & operator [] (int index) const { 61 return elements[index]; 62 } 63 64 };
因为对象中包含地址且存放的是为每个对象动态分配的内存空间,所以这个类中必须定义释构函数,拷贝构造函数,等于号操作符,它们位于38--‐49行。在32--‐36行定义了一个默认构造函数,它构造一个空的容器。第34行本来只需要分配0个长度的数组,但是new 操作符申请的内存空间的最小长度为1。\t\r ?\t\r ?
函数ensureCapacity0在容器类对象所封装的数组容量不够大的时候增加它的容量,并用函数copy0恢复来的内容。因为在这个容器类中,实际上存放double变量的个数就是
capacity,所以,在
52行中返回capacity,在56行中添加
元素后的大小为capacity + 1。因为在函数ensureCapacity0中capacity 被赋值为新的大小,所以在57行中被添加在最后的元素的索引为capacity - 1。\t\r ?
2. 模板容器类\t\r ?
以上所定义的容器类Vector只能用来存储double类型的变量。如果我们需要定义一个,容器类Vector用来存储string类型的对象,那么我们只需要把中的各个double替换成
string
即可。但是,这产生了几乎重复的代码。\t\r ?
我们可不可以定义一个单一的容器类Vector,它能存放
double
类型的变量,或者string类型的对象,或者任意类型
的对象呢?也就是说,我们可不可以定义一个容器类Vector,它的元素可以是未知的类型呢?在C++中,我们可以定义带有未知类型参数的类,这种类叫做模板类。模板类的最主要
用途就是模板容器类。我们即将定义一个模板容器类,它的元素的类型为该模板类的类型参数。\t\r ?
在讲述模板容器类版本的Vector之前,我们先看看如何使用这个模板容器类。\t\r ?
1 class Student 2 {
3 public:
4 int id;
5 string name; 6 }; 7
8 ostream & operator << (ostream & out, 9 const Student & student) {
10 out << \ << student.id << 11 \ << student.name; 12 return out; 13 } 14
15 istream & operator >> (istream & in, 16 Student & student) {