C++沉思录之三——设计容器类
一、对容器的基本认识
总的来说,容器应该包含放在其中的对象的副本,而不是对象本身。
二、复制容器意味着什么?
通常将容器成为模板,而容器内的对象的类型就是模板参数。Container<T>
显然,如果复制容器只不过简单地使两个容器指向同一个底层对象,而不是复制容器内的元素,那么效率就会提高很多。毕竟,大多数复制是在调用函数时发生的,像下面这样编写代码会犯一个很常见的错误:
void f(Container<T> );
而用
void f(const Constainer<T>& );
就会好很多。
复制容器意味着复制容器内的所有元素,这样做的开销是很大的。
三、如何获取容器内的元素
从Container中取出对象时,应该得到类型T还是T&的对象呢?
第一种观点:从上面所述我们知道,容器存放的是对象的副本,而不是对象本身。而存放对象副本只发生一次就可以了,然而,从容器中取出对象的操作常常有很多次,所以,避免获取容器中的对象时的复制操作所带来的额外开销,要比避免想容器中插入对象时的复制操作所带来的额外开销重要得多。取出来的应该是对象的引用
第二种观点:上面关于效率的讨论也不是绝对的重要。如果取出来的是对象的引用,会导致一些问题。所以取出来的应该是对象的副本。
四、下面,根据以上分析设计一个容器:
容器特点:
1. 定长,长度为零或者大于零的整数;
2. 操作符[]既可以读容器,也可以写容器;
3. 存在从数组到指向它的第一个元素的指针的转换;
4. 不允许容器的赋值和复制。
设计如下:
// Array_designer.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include <iostream> using namespace std; template<class T> class Array { public: Array(): data(0), len(0) { } Array(unsigned size): len(size), data(new T[size]) { } ~Array() { delete []data; } const T& operator[] (unsigned n) const { if(n >= len || data == 0) { throw "Array subscript out of range"; } return data[n]; } T& operator[] (unsigned n) { if(n >= len || data == 0) { throw "Array subscript out of range"; } return data[n]; } operator const T*() const { return data; } operator T*() { return data; } private: T *data; unsigned len; Array(const Array& a);//copy constructor Array& operator=(const Array&); }; int _tmain(int argc, _TCHAR* argv[]) { Array<int> a(10);// not Array<int> a[10]; int *start = a; int *end = a + 10; int i = 0; while(start != end) { *start++ = i++; } start = a; end = a + 10; while(start != end) { cout<<*start++<<"\t"; } cout<<a[(unsigned)0]; system("pause"); return 0; }