C++基础6 模板

函数模板

模板的意义:对类型也可以进行参数化

#include 
using namespace std;
template 
bool compare(T a, T b)
{
	return a > b;
}
int main()
{
	compare(10, 20);
	return 0;
}

在函数调用点,编译器用用户指定的类型,从原模版实例化一份函数代码出来。

当用户没有指定类型时,模板会进行实参推演,可以根据用户传入的实参的类型,来推导出模板类型参数的具体类型

函数模板不进行编译,模板函数才是要进行编译的

当对于某些类型来说,依赖编译器默认实例化的模板代码,代码处理逻辑是错误时,就要进行模板特例化(特殊的实例化,不是编译器提供的,而是用户提供的)

下面将针对compare函数模板,提供const char *类型的特例化版本

#include 
using namespace std;
template 
bool compare(T a, T b)
{
	return a > b;
}
template <>
bool compare(const char* a, const char* b)
{
	cout << "const cha *" << endl;
	return strcmp(a, b);
}
int main()
{
	compare(10, 20);
	compare("aaa", "bbb");
	return 0;
}

编译器会优先把compare处理成函数,没有再去找模板

#include 
using namespace std;
template 
bool compare(T a, T b)
{
	return a > b;
}
template <>
bool compare(const char* a, const char* b)
{
	cout << "const cha *" << endl;
	return strcmp(a, b);
}
bool compare(const char* a, const char* b)
{
	cout << "const cha " << endl;
	return strcmp(a, b);
}
int main()
{
	compare(10, 20);
	compare("aaa", "bbb");
	compare("aaa", "bbb");
	return 0;
}

模板代码不能在一个文件定义,在另一个文件中进行使用的

模板代码调用之前,一定要看到模板被定义的地方,这样的话,模板才能够进行正常的实例化,产生能够被编译器编译的代码

所以,模板代码都是放在头文件中,然后再源文件当中直接进行#include包含

类模板

模板的非类型参数 必须是整数类型(整数或者地址/引用)都是常量,只能使用不能修改

#include 
using namespace std;
template
void sort(T* arr)
{
	for (int i = 0; i < SIZE -1; ++i)
	{
		for (int y = 0; y < SIZE - i - 1; ++y)
		{
			if (arr[y] > arr[y + 1])
			{
				int temp = arr[y];
				arr[y] = arr[y+1];
				arr[y + 1] = temp;
			}
		}
	}
}
int main()
{
	int arr[] = { 35,25,48,69,20,10,3 };
	int size = 7;
	sort(arr);
	for (int val : arr)
	{
		cout << val << " ";
	}
	cout << endl;
	return 0;
}

类模板

模板函数+类型参数列表 = 类名称

构造和析构函数不用加,其它出现模板的地方都加上类型参数列表

#include 
using namespace std;
template
class SetStack
{
public:
	SetStack(int size = 10)
		:_stack(new int[10])
		, _top(0)
		,_size(size)
	{}
	~SetStack()
	{
		delete[]_stack;
		_stack = nullptr;
	}
	SetStack(const SetStack& other)
		:_top(other._top)
		,_size(other._size)
	{
		_stack = new T[_size];
		for (int i = 0; i < _top; ++i)
		{
			_stack[i] = other._stack[i];
		}
	}
	SetStack& operator=(const SetStack& other)
	{
		if (this == &other)
		{
			return *this;
		}
		delete[]_stack;
		_top = other._top;
		_size = other._size;
		_stack = new T[_size];
		for (int i = 0; i < _top; ++i)
		{
			_stack[i] = other._stack[i];
		}
		return *this;
	}
	void push(int val)
	{
		if (full())
		{
			expend();
		}
		_stack[_top++] = val;
	}
	void pop()
	{
		if (empty())
		{
			return;
		}
		--_top;
	}
	T top() const
	{
		if (empty())
		{
			throw "stack is empty!";
		}
		return _stack[_top - 1];
	}
	bool full() const
	{
		return _top == _size;
	}
	bool empty() const
	{
		return _top == 0;
	}
private:
	T* _stack;
	int _top;
	int _size;
	void expend()
	{
		T* temp = new T[_size * 2];
		for (int i = 0; i < _top; ++i)
		{
			temp[i] = _stack[i];
		}
		delete[]_stack;
		_stack = temp;
		_size *= 2;
	}
};
int main()
{
	SetStack s1;
	s1.push(20);
	s1.push(30);
	s1.push(80);
	s1.push(50);
	cout << s1.top() << endl;;
	s1.pop();
	cout << s1.top() << endl;;
	return 0;
}

实现C++STL向量容器vector

以下是没有加空间配置器allocator

#include 
using namespace std;
template
class vector
{
public:
	vector(int size = 10)
		:_first(new T[size])
		,_last(_first)
		,_end(_first+size)
	{

	}
	~vector()
	{
		delete[]_first;
		_first = _last = _end = nullptr;
	}
	vector(const vector & other)
	{
		_first = new T[other._end - other._first];
		for (int i = 0; i < (other._last - other._first); i++)
		{
			_first[i] = other._first[i];
		}
		_last = _first + other._last - other._first;
		_end = _first + other._end - other._first;
	}
	vector& operator=(const vector& other)
	{
		if (this == &other)
		{
			return *this;
		}
		delete[]_first;
		_first = new T[other._end - other._first];
		for (int i = 0; i < (other._last - other._first); i++)
		{
			_first[i] = other._first[i];
		}
		_last = _first + other._last - other._first;
		_end = _first + other._end - other._first;
		return *this;
	}
	void push_back(T val)
	{
		if (full())
		{
			expand();
		}
		*_last++ = val;
	}
	void pop_back()
	{
		if (empty())
		{
			return;
		}
		--_last;
	}
	T back() const
	{
		if (empty())
		{
			throw "vector is empty";
		}
		return *(_last - 1);
	}
	bool full() const
	{
		return _last == _end;
	}
	bool empty() const
	{
		return _first == _last;
	}
	int size() const
	{
		return _last - _first;
	}
private:
	T* _first;
	T* _last;
	T* _end;
	void expand()
	{
		int size = _end - _first;
		T* temp = new T[2 * size];
		for (int i = 0; i < size; i++)
		{
			temp[i] = _first[i];
		}
		delete[]_first;
		_first = temp;
		_end = _first + size*2;
		_last = _first + size;
	}
};
int main()
{
	vector vec;
	for (int i = 0; i < 20; i++)
	{
		vec.push_back(rand() % 100);
	}
	while (!vec.empty())
	{
		cout << vec.back() << " ";
		vec.pop_back();
	}
	cout << endl;
	return 0;
}

理解空间配置器allocator的重要性

class test
{
public:
	test()
	{
		cout << "test()" << endl;
	}
	~test()
	{
		cout << "~test()" << endl;
	}
};
int main()
{
	vector vec;
	return 0;
}

当我们用没有自己写的没有空间配置器的vector,按照上述代码,会根据vector构造函数的参数给我们构造十个test对象,这显然是不合理的,并不是我们想要得,我们需要把开辟空间和构造对象分开,析构函数析构有效元素(而不是释放每个元素)再开辟释放内存空间,并且pop_back也需要析构对象而不释放内存,所以要把析构对象和释放内存分开

C++基础6 模板_第1张图片

空间配置器allocator只做四件事  空间开辟/空间释放    对象构造/对象析构 

下面是加了空间配置器allocator的自定义vector

#include 
using namespace std;
template
struct Allocator
{
	T* allocate(size_t size)
	{
		return (T*)malloc(sizeof(T) * size);
	}
	void deallocate(void* p)
	{
		free(p);
	}
	void construct(T* p, const T& val)
	{
		new (p) T(val); //定位new
	}
	void destroy(T* p)
	{
		p->~T();
	}
};
template>
class vector //容器底层的空间开辟,空间释放,对象构造,对象析构都通过allocator空间配置器
{
public:
	vector(int size = 10)
		//:_first(new T[size])
		:_first(_allocator.allocate(size))
		,_last(_first)
		,_end(_first+size)
	{

	}
	~vector()
	{
		//delete[]_first;
		for (T* p = _first; p != _last; ++p)
		{
			_allocator.destroy(p); //析构
		}
		_allocator.deallocate(_first); //释放内存
		_first = _last = _end = nullptr;
	}
	vector(const vector & other)
	{
		//_first = new T[other._end - other._first];
		_first = _allocator.allocate(other._end - other._first);
		for (int i = 0; i < (other._last - other._first); i++)
		{
			//_first[i] = other._first[i];
			_allocator.construct(_first+i, other._first[i]);
		}
		_last = _first + other._last - other._first;
		_end = _first + other._end - other._first;
	}
	vector& operator=(const vector& other)
	{
		if (this == &other)
		{
			return *this;
		}
		//delete[]_first;
		for (T* p = _first; p != _last; ++p)
		{
			_allocator.destroy(p); //析构
		}
		_allocator.deallocate(_first); //释放内存
		//_first = new T[other._end - other._first];
		_first = _allocator.allocate(other._end - other._first);
		for (int i = 0; i < (other._last - other._first); i++)
		{
			//_first[i] = other._first[i];
			_allocator.construct(_first + i, other._first[i]);
		}
		_last = _first + other._last - other._first;
		_end = _first + other._end - other._first;
		return *this;
	}
	void push_back(T val)
	{
		if (full())
		{
			expand();
		}
		//*_last++ = val;
		_allocator.construct(_last, val);
		_last++;
	}
	void pop_back()
	{
		if (empty())
		{
			return;
		}
		//--_last;
		--_last;
		_allocator.deallocate(_last);
	}
	T back() const
	{
		if (empty())
		{
			throw "vector is empty";
		}
		return *(_last - 1);
	}
	bool full() const
	{
		return _last == _end;
	}
	bool empty() const
	{
		return _first == _last;
	}
	int size() const
	{
		return _last - _first;
	}
private:
	T* _first;
	T* _last;
	T* _end;
	Alloc _allocator;
	void expand()
	{
		int size = _end - _first;
		//T* temp = new T[2 * size];
		T* temp = _allocator.allocate(2*size);
		for (int i = 0; i < size; i++)
		{
			_allocator.construct(temp+i, _first[i]);
			//temp[i] = _first[i];
		}
		//delete[]_first;
		for (T* p = _first; p != _last; ++p)
		{
			_allocator.destroy(p); //析构
		}
		_allocator.deallocate(_first); //释放内存
		_first = temp;
		_end = _first + size*2;
		_last = _first + size;
	}
};
class test
{
public:
	test()
	{
		cout << "test()" << endl;
	}
	~test()
	{
		cout << "~test()" << endl;
	}
};
int main()
{
	vector vec;
	test t1;
	vec.push_back(t1);
	return 0;
}

你可能感兴趣的:(C++基础,c++,开发语言)