有关模板类----实现Vector的类模板

由上一篇的文章中 ,我们已经知道,模板是一个代码生成器,可以极大效率提高我们的工作效率,实现让编译器为我们产生代码的机制

在C++面向对象中,我们在对类的使用上,已经达到了最少80%了,因此,模板类的使用,将极大的提高程序的运行效率,节省程序的运行时间。

(一)概念区分

类模板也称类属类或类生产类,允许用户为类定义一种模式,使得类中的某些数据成员,默写成员函数的参数,某些成员参数的返回值,能够取任意类型(包括系统预定义和用户自定义),如果一个类中数据成员的数据类型不能确定,或者是某个成员函数的参数返回值的类型不能确定,就必须将此类声明为模板,他的存在不是代表一个具体的,实际的类,而是代表一类类。

类模板由三种类型的模板参数:类型模板参数,非类型模板参数和模板的模板参数。

模板类:是类模板实例化的的一个产物,可以从类模板派生出新的类,既可以派生类模板,也可以派生非类模板,模板类的重点是类表示由一个模板生成而来的类,模板类与平台无关,具有可移植性,可用于基本数据类型,可用来创建动态增长和减小的数据结构。

模板类的实例化:只要有一种不同的类型,编译器就会实例化出一个对应的类。

(二)有关Vector模板的实现

Vector:是用来连续的存储数据的,类似于顺序表,在其中任意位置的插入或者删除的效率比较低,但是对内存碎片存在的就比较少,在某些情况下,对内存的使用率比较好。

#define _CRT_SECURE_NO_WARNINGS 1

//注:memcpy会出现浅拷贝的问题,因此在拷贝元素时,应该慎用

#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
#include

using namespace std;

template
class Vector
{
public:
	Vector()//构造函数,顺序表为空
		:_start(0)
		, _finish(0)
		, _endOfStorage(0)
	{}

	Vector(const T*arr, size_t size);//声明,顺序表中已经存放元素

	Vector(const Vector& t) //拷贝构造函数
	{
		size_t size = t.Size();
		_start = new T[size];
		for (size_t i = 0; i < size; ++i)
		{
			_start[i] = t._start[i];
		}
		_finish = _start + size;
		_endOfStorage = _finish;
	}

	Vector&operator=(const Vector&v)//赋值运算符的重载
	{
		if (this != &v)
		{
			size_t size = v.Size();
			_start = new T[size];
			for (size_t i = 0; i < size; ++i)
			{
				_start[i] = v._start[i];
			}
		}
		return*this;
	}

	void PushBack(const T& data)//尾插,注意在此处,const修饰的是data
	{
		CheckCapacity();
		*_finish++ = data;//改变_finish的位置,从而将数据插入在上面
	}

	void PopBack()//尾删,直接改变顺序表中_finish的位置
	{
		--_finish;
	}

	void Insert(size_t pos, const T& data)//任意位置的插入
	{
		//检查pos是否合法
		assert(pos < Size());//检查当前插入的位置是否有效
		CheckCapacity();
		CheckCapacity();
		size_t i = 0;
		//搬移元素
		for (i = Size(); i > pos; --i)
		{
			_start[i] = _start[i - 1];
		}
		_start[pos] = data;
		++_finish;
	}

	void Erase(size_t pos)//任意位置删除
	{
		assert(pos < Size());
		size_t i = 0;
		for (i = pos; i < Size() - 1; ++i)//减1的原因是:防止拿到最大元素处的后一个元素
		{
			_start[i] = _start[i + 1];
		}
		--_finish;
	}

	size_t Size()const//元素的个数
	{
		return _finish - _start;
	}

	size_t Capacity()const//容量
	{
		return  _endOfStorage - _start;
	}

	bool Empty()const//判断顺序表是否为空
	{
		return (Size() == 0);//_start==_finish;
	}

	void Resize(size_t newSize, const T& data = T())//将顺序表中的size改变到newSize
	{
		size_t OldSize = Size();//将顺序表中的size做一个记录,从而方便下面的比较
		size_t capacity = Capacity();
		if (newSize < OldSize)
		{
			_finish = _start + newSize;//改变里面存储空间的大小
		}
		else if ((OldSize < newSize) && (newSize < capacity))
		{
			for (size_t i = OldSize; i < newSize; ++i)//将需要拷贝的数据拷贝下来
			{
				_start[i] = data;
			}
			_finish = _start + newSize;
		}
		else//此种情况为,新的顺序表的大小,比原来顺序表中的空间都大,因此需要开辟新的空间
		{
			T*tmp = new T[newSize];
			for (size_t i = 0; i < OldSize; ++i)//先拷贝旧空间的元素
			{
				tmp[i] = _start[i];
			}
			for (size_t j = OldSize; j < newSize; ++j)//将新的元素填充剩下的这段空间
			{
				tmp[j] = data;
			}
			delete[]_start;
			_start = tmp;
			_finish = _start + newSize;
			_endOfStorage = _start + newSize;
		}
	}


	T& operator[](size_t index)//下标运算符重载(成对出现)随机访问
	{
		return _start[index];
	}
	const T& operator[](size_t index)const
	{
		return _start[index];
	}

	T& Front()//返回最开始的元素
	{
		return *_start;//_start表示指向首元素的指针,对其解引用表示取出首地址的内容
	}
	const T& Front()const
	{
		return *_start;
	}

	T& Back()
	{
		return *(_finish - 1);//同Front
	}

	const T& Back()const
	{
		return *(_finish - 1);
	}

	void Clear()//置空顺序表
	{
		_finish = _start;
	}

	template//不是类的成员函数
	friend ostream&operator<<(ostream&_cout, const Vector&t)//输出运算符重载
	{
		for (size_t i = 0; i < t.Size(); ++i)
		{
			_cout << t[i] << " ";
		}

		//memcpy(_Start, t._start, sizeof(t));
		return _cout;
	}

	void Display()
	{
		size_t size = Size();
		for (size_t i = 0; i < size; ++i)
		{
			cout << _start[i];
			cout << " ";
		}
		cout << endl;
	}

	~Vector()//析构函数
	{
		if (_start != NULL)
		{
			delete[]_start;
			_start = NULL;
			_finish = NULL;
			_endOfStorage = NULL;

		}
	}

private:
	void CheckCapacity()
	{
		size_t size = Size();
		size_t capacity = Capacity();
		if (size >= capacity)
		{
			size_t newCapacity = capacity * 2 + 3;
			//申请新空间
			T*_tmp = new T[newCapacity];
			//拷贝元素
			for (size_t i = 0; i < size; ++i)
			{
				_tmp[i] = _start[i];
			}

			//释放旧空间
			if (_start)//防止释放的空间为空,从而导致程序崩溃
				delete[] _start;
			_start = _tmp;
			_finish = _start + size;
			_endOfStorage = _start + newCapacity;
		}
	}
private:
	T*_start;  //表示顺序的开始,空间起始位置
	T*_finish;  //表示顺序表中存储元素的多少
	T*_endOfStorage; //表示顺序表的容量
};

template
Vector::Vector(const T*arr, size_t size)//有元素,1、开辟大小 2、复制数据
:_start(new T[size])
, _finish(_start + size)
, _endOfStorage(_start + size)
{
	//memcpy(_start, arr, sizeof(T)*size)//会存在浅拷贝的问题
	for (size_t i = 0; i < size; ++i)//拷贝元素
	{
		_start[i] = arr[i];
	}
}


class String
{
public:
	String(const char* pStr = "")
	{
		if (_pStr == NULL)
		{
			_pStr = new char[1];
			(*_pStr) = '\0';
		}
		else
		{
			_pStr = new char[strlen(pStr) + 1];
			strcpy(_pStr, pStr);
		}
	}

	/*String(const String &s)//拷贝构造函数
	:_pStr(NULL)
	{
	String tmp(s._pStr);
	swap(_pStr, tmp);
	}*/

	String(const String &s)
		:_pStr(new char[strlen(s._pStr) + 1])
	{
		strcpy(_pStr, s._pStr);
	}

	String& operator=(const String&s)
	{
		if (this != &s)//检测是不是自己给自己赋值
		{
			char*tmp = new char[strlen(s._pStr) + 1];
			strcpy(tmp, s._pStr);

			delete[] _pStr;
			_pStr = NULL;
			_pStr = tmp;
		}
		return *this;
	}
	friend ostream&operator<<(ostream&_cout, const String&t)//输出运算符重载
	{
		_cout << t._pStr;
		return _cout;
	}

	~String()
	{
		if (_pStr != NULL)
		{
			delete[] _pStr;
			_pStr = NULL;
		}
	}

private:
	char*_pStr;
};

#if 0
void FunTest1()
{
	//Vector s1;
	int arr[] = { 1, 2, 3, 4 };
	Vector s2(arr, sizeof(arr) / sizeof(arr[0]));
	//Vector s3(s2);
	//cout << s2 << endl;
	//s1 = s2;
	//cout << s1 << endl;
	cout << "size= " << s2.Size() << endl;
	cout << "capacity= " << s2.Capacity() << endl;
	cout << s2 << endl;
	s2.Display();

	s2.PushBack(5);
	s2.PushBack(6);
	s2.PushBack(7);
	cout << "size= " << s2.Size() << endl;
	cout << "capacity= " << s2.Capacity() << endl;
	cout << s2 << endl;
	s2.Display();

	s2.PopBack();
	s2.PopBack();
	cout << "size= " << s2.Size() << endl;
	cout << "capacity= " << s2.Capacity() << endl;
	cout << s2 << endl;
	s2.Display();

	s2.Erase(2);
	cout << "size= " << s2.Size() << endl;
	cout << "capacity= " << s2.Capacity() << endl;
	s2.Insert(3,7);
	cout << "size= " << s2.Size() << endl;
	cout << "capacity= " << s2.Capacity() << endl;
	cout << s2 << endl;
	s2.Display();

	s2.Resize(4);
	cout << "size= " << s2.Size() << endl;
	cout << "capacity= " << s2.Capacity() << endl;
	s2.Display();

	s2.Resize(30);
	cout << "size= " << s2.Size() << endl;
	cout << "capacity= " << s2.Capacity() << endl;
	cout << s2 << endl;
	s2.Display();
}
#endif
void FunTestString()
{
	Vector s;
	s.PushBack("1111");
	s.PushBack("2222");
	s.PushBack("3333");
	cout << "size= " << s.Size() << endl;
	cout << "capacity= " << s.Capacity() << endl;
	cout << s << endl;

	s.PushBack("4444");
	cout << "size= " << s.Size() << endl;
	cout << "capacity= " << s.Capacity() << endl;
	cout << s << endl;

	s.PopBack();
	cout << "size= " << s.Size() << endl;
	cout << "capacity= " << s.Capacity() << endl;
	cout << s << endl;

	s.Insert(2, "5555");
	cout << "size= " << s.Size() << endl;
	cout << "capacity= " << s.Capacity() << endl;
	cout << s << endl;

	s.Resize(4);
	cout << "size= " << s.Size() << endl;
	cout << "capacity= " << s.Capacity() << endl;
	cout << s << endl;

	s.Resize(20,"0000");
	cout << "size= " << s.Size() << endl;
	cout << "capacity= " << s.Capacity() << endl;
	cout << s << endl;

	s.Clear();
	cout << "size= " << s.Size() << endl;
	cout << "capacity= " << s.Capacity() << endl;
	cout << s << endl;
}

int main()
{
	FunTestString();
	system("pause");
	return 0;
}
由上面可以看出,由于在模板中对于输出运算符的重载,存在着一定的问题,因此上面对于String类型与内置类型分别测试。

结果如下:

String类型

有关模板类----实现Vector的类模板_第1张图片

内置类型:
有关模板类----实现Vector的类模板_第2张图片



你可能感兴趣的:(简单项目,c++)