首页 新闻 论坛 群组 Blog 文档 下载 读书 Tag 网摘 搜索 开源 FAQ 第二书店 博文视点 程序员
频道: 研发 数据库 中间件 信息化 视频 .NET Java 游戏 移动 服务: 人才 外包 培训
    图书品种:235680
       
热门搜索: ASP.NET Ajax Spring Hibernate Java

6.5 参数化vector类

下面创建一个容器类来改进基本的C++数组。在C和C++中,数组的弱点是容易产生越界错误,从而导致很难找到运行时的bug。现在将下面这个参数化的类命名为vector(原因是我们希望能讨论并理解标准模板库(STL)中的类std::vector),类中使用了迭代器(iterator)和算法(algorithm)。一个迭代器就是一个指针或者类似指针的变量,它能够遍历和访问容器内的元素。

文件 vect_it.h

// Template-based vector type

template <class T>

class vector {

public:

   typedef T* iterator;

   explicit vector(int n = 100);           // make size n array

   vector(const vector<T>& v);         // copy vector

   vector(const T a[], int n);              // copy an array

   ~vector() { delete []p; }

   iterator begin() { return p; }

   iterator end() { return p + size; }

   T& operator[](int i);                     // range-checked element

   vector<T>& operator=(const vector<T>& v);

private:

   T* p;                                    // base pointer

   int size;                         // number of elements

};

基本上,template定义可以在类中任何一个地方使用T。T类型的值作为独立元素存储,因此,私有基指针p声明的类型是T。

在文件作用域中成员函数的定义要使用作用域解析标记类名<T>。下面的vector<T>的构造函数使用T作为new的类型说明:

template <class T>

vector<T>::vector(int n) : size(n)

{

   assert(n > 0);

   p = new T[size];

   assert(p != 0);

}

因为在类声明中将100定义为n的默认参数,所以前述代码是一个默认构造函数。这里使用关键字explicit禁止从int类型到vector类型的转换,断言用于保证在给出适当输入的时候允许构造函数执行它约定的职责。

template <class T>

vector<T>::vector(const T a[], int n)

{

   assert(n > 0);

   size = n;

   p = new T[size];

   assert(p != 0);

   for (int i = 0; i < size; ++i)

      p[i] = a[i];

}

这个构造函数将一个普通的数组转化为vector。复制构造函数实现了对vector v的深复制。

template <class T>

vector<T>::vector(const vector<T>& v)

{

   size = v.size;

   p = new T[size];

   assert(p != 0);

   for (int i = 0; i < size; ++i)

     p[i] = v.p[i];

}

下面的代码重载了[]运算符,用于实现vector的索引功能。[]运算符的返回值类型是“T的引用”,原因是返回值是存储在容器中的各项内容的别名。使用这样的返回类型使得[]运算符可以作为左值访问容器中的各项内容。

template <class T> T& vector<T>::operator[](int i)

{

   assert (i >= 0 && i < size);

   return p[i];

}

注意,使用断言测试确保数组不越界。在重载operator[]以后,就可以像访问C++基本数组一样访问vector了。这里也需要提供重载的赋值运算符。

template <class T>

vector<T>& vector<T>::operator=(const vector<T>& v)

{

   assert(v.size == size);

   for (int i = 0; i < size; ++i)

      p[i] = v.p[i];

   return *this;

}

客户代码几乎像没有使用参数化声明一样简单。要使用这些参数化声明,只需简单地在尖括号里添加能够实例化模板的特定类型。这些类型可以是基本类型,例如示例程序中的int类型,也可以是用户自定义类型。下面的代码中使用了这些模板。

文件 vect_it.cpp

int main()

{

   vector<double> v(5);

   vector<double>::iterator p;

   int i = 0;

   for (p = v.begin(); p != v.end(); ++p)

      *p = 1.5 + i++;

   do {

      --p;

      cout << *p << " , ";

   } while (p != v.begin());

   cout << endl;

}

程序的输出结果如下:

5.5, 4.5, 3.5, 2.5, 1.5,

这些值按照它们存储时的反序排列,这是从迭代器v.end()开始反向扫描形成的结果(见本章习题6)。

查看所有评论(0)条】

最近评论



正在载入评论列表...
热点评论