04 C++模板

01 函数模板

函数模板是不进行编译的,因为类型还未知。模板函数才是要被编译器所编译的。

// 定义一个函数模板
template <typename T>
T add(T a, T b) {
    return a + b;
}

模板函数是指通过模板定义的函数,例如下面的 add函数 就是一个模板函数。
模板的实例化
在函数的调用点进行实例化

cout << add(3, 4) << endl;       // 编译器生成int类型的add函数
cout << add(3.5, 4.5) << endl;   // 编译器生成double类型的add函数

模极类型参数
可以使用typename或者class定义模板参数列表,通常使用typename

template <typename T>
T multiply(T a, T b) {
    return a * b;
}

在上面程序中,T 就是一个模板类型参数。

模板非类型参数

template<tyename T, int SIZE>
// SIZE为模板非类型参数

模板非类型参数都是常量,只能使用,不能修改
允许模板在编译时使用常量值;非类型参数可以是整数、枚举值、指针或引用等,这些参数在编译时必须是常量;通常用于数组的大小、固定大小的数据结构或编译时计算。

模板的实参推演
可以根据用户传入的实参的类型,来推导出模板类型参数的具体类型

模板的特例化(专用化)是特殊(不是编译器提供的,而是用户提供的)的实例化

template <typename T>
void display(T a) {
    cout << "Generic template: " << a << endl;
}

// 为int类型特例化
template <>
void display<int>(int a) {
    cout << "Specialized template for int: " << a << endl;
}

int main() {
    display(10);         // 调用特例化的模板
    display(3.14);       // 调用通用模板
    display("hello");    // 调用通用模板
    return 0;
}

函数模板、模牧的特例化、非模板函数的重载关系
编译器会优先找非模板函数(普通函数),没有才去找compare模板函数

模版代码是不能在一个文件中定义,在另外一个文件中使用的。
模板代码调用之前,一定要看到模板定义的地方,这样模板才能进行正常的实例化,产生能够被编译器编译的代码。
所以,模板代码都是放在头文件中的,然后在源文件当中直接进行#include包含。

// 函数模板
template<typename T> // 定义一个模板参数列表
bool compare(T a,T b) // compare是一个函数模板
{
	return a > b;
}
/*
在函数的调用点,编译器用用户指定的类型,从原模板实例化一份函数代码出来
模板函数
bool compare<int>(int a,int b)
{
	return a > b;
}
*/
// 针对compare函数模板,提供const char*类型的特例化版本
template<>
bool compare<const char*>(const char *a, const char *b)
{
	return strcmp(a, b) > 0;
}

// 非模板函数 - 普通函数
bool compare(const char *a, const char *b)
{
	return strcmp(a, b) > 0;
}
int main()
{
	// 函数的调用点
	compare<int>(10, 20);
	
	// 函数模板的实参推演
	compare(10,20);
	compare<int>(10,30.5);

	// 函数模板实参的推演 T const char*
	// 对于某些类型,依赖编译器默认实例化的模板代码,代码逻辑是错误的
	compare("aaa", "bbb");
	
	return 0;
}

02 类模板

template<typename T> 
class SeqStack // 模板名称+类型参数列表 = 类名称
{
public:
	// 构造和析构函数名不用加<T>,其它出现模板的地方都加上类型参数列表
	SeqStack (int size = 10)
		: _psatck(new T[size])
		, _top(0)
		, _size(size)
	{}
	~SeqStack()
	{
		delete[]_pstack;
		_pstack = nullptr;
	}
	
	SeqStack(const SeqStack<T> &stack);
		:_top(stack._top)
		,_size(stack._size)
	{
		_pstack = new T[_size];
		//不要使用memcopy拷贝
		for(int i = 0;i < _top; ++i)
		{
			_pstack[i] = stack._pstack[i];
		}
	}
	
	SeqStack<T>& operator=(const SeqStack<T> &stack);
	{
		if (this == &stack)
			return *this;
		
		delete[]_pstack;
		
		_top = stack._top;
		_size = stack._size;
		_pstack = new T[_size];
		for(int i = 0;i < _top; ++i)
		{
			_pstack[i] = stack._pstack[i];
		}
		return *this;
	}
	 
	void push (const T &val); // 入栈操作
	
	void pop(); // 出栈操作
	{
		if(empty())
			return;
		--_top;
	}
	T top()const; // 返回栈顶元素
	{
		if(empty())
			throw "stack is empty!"; // 抛异常也代表函数逻辑结束
		return _pstack[_top - 1];
	}
	boo full()const; { return _top == _size;} // 栈满
	boll empty()const; {return _top == 0;} // 栈空
private:
	T *_pstack;
	int _top;
	int _size;

	 // 以顺序栈底层数组2倍的方式扩容
	 void expand()
	 {
	 	T *ptmp = new T[_size * 2];
	 	for (int i = 0;i < _top; ++i)
	 	{
	 		ptmp[i] = _pstack[i];
	 	}
	 	delete []_pstack;
	 	_pstack = ptmp;
	 	_size *= 2} 
};
template<typename T>
void SeqStack<T>::push(const T &val) // 入栈操作
{
		if(full())
			expand();
		_pstack[_top++] = val;
}

03 实现C++ STL 向量容器vector

// 使用类模板实现C++ STL里面的一个顺序容器 vector 向量容器
#include <iostream>
using namespace std;

template<typename T>
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<T>& rhs)
	{
		int size = rhs._end - rhs._first;
		_first = new T[size];
		int len = rhs._last - rhs._first;
		for (int i = 0; i < len; ++i)
		{
			_first[i] = rhs._first[i];
		}
		_last = _first + len;
		_end = _first + size;
	}
	vector<T>& operator=(const vector<T>& rhs)
	{
		if (this == &rhs)
			return *this;
		delete[]_first;
		int size = rhs._end - rhs._first;
		_first = new T[size];
		int len = rhs._last - rhs._first;
		for (int i = 0; i < len; ++i)
		{
			_first[i] = rhs._first[i];
		}
		_last = _first + len;
		_end = _first + size;
		return *this;
	}
	void push_back(const T& val) // 向容器末尾添加元素
	{
		if (full())
			expand();
		*_last++ = val;
	}
	void pop_back() // 从容器末尾删除元素
	{
		if (empty())
			return;
		--_last;
	}
	T back()const // 返回容器末尾的元素的值
	{
		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;
		int newSize = size * 2;
		T* newFirst = new T[newSize];
		for (int i = 0; i < size; ++i)
		{
			newFirst[i] = _first[i];
		}
		delete[] _first;
		_first = newFirst;
		_last = _first + size;
		_end = _first + newSize;
	}
};

int main()
{
	vector<int> vec;
	for (int i = 0; i < 20; ++i)
	{
		vec.push_back(rand() % 100);
	}
	vec.pop_back();
	while (!vec.empty())
	{
		cout << vec.back() << " ";
		vec.pop_back();
	}
	cout << endl;
	return 0;
}
  • 11
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值