函数模板和类模板

在C++语言中,函数声明和定义需要明确指定函数名及其参数类型,这是理解函数重载的重要概念。

函数模板

C++函数模板是一种强大的泛型编程工具,它允许我们对数据类型进行参数化,从而实现代码的高度复用。模板的核心意义在于将算法与数据类型解耦,使同一段代码可以适用于不同的数据类型

template<typename T>//定义一个模板参数列表
bool compare(T a,T b) //compare是一个函数模板
{
	return a>b;
}

上述定义的这段代码就可以支持如int、float、double类型的数据比较。

函数模板的实例化

在函数调用点进行实例化是指在使用函数模板时,编译器会根据传入的实参在调用点自动生成对应的具体函数代码。
具体过程可以总结为:

  1. 编译器在编译时遇到函数模板调用语句
  2. 根据实参类型推导模板参数
  3. 并实例化对应类型的模板函数
  4. 编译生成的目标代码中会包含这个模板函数
/*
实例化的int型模板函数
bool compare<int>(int a,int b)
{
	return a>b;
}
实例化的double型模板函数
bool compare<double>(double a,double b)
{
	return a>b;
}
*/
int main()
{
	//在函数调用点,编译器根据用户指定的类型,从原模版实例化一份代码出来
	//叫做模板函数
	compare<int> (10,20);
	compare<double>(10.5,20.5);
}

如上述代码,由于compare是函数模板,并且调用的时候分别传入了int类型的实参和double类型的实参,于是从原模板中分别实例化了int和double的模板函数。

函数模板的特例化

特例化:模板本来是一组通用逻辑的实现,但是对于某些特定的参数类型来说,通用的逻辑实现可能不能满足要求,这时就需要针对这些特殊的类型去实现一个特例模板,即模板的特例化。

函数模板特例化,是将模板参数全部指定成特定的类型(并对这个类型的逻辑进行修改),但不等价于函数重载,两者不要混淆。

/*针对compare这个模板函数,能适用于大部分数据类型,如int ,double,以及简单对象,但是也有特例
如compare("aaa","bbb"),根据函数推演,其应该是
bool <const char *>(const char *,const char *)
{
return a<b;
}
这样比较的是a和b两个地址的大小,而非字典序大小,
针对这种情况,提供const char *这个类型的特例化版本
*/
template<>
bool compare(const char *a,const char *b)
{
	return strcmp(a,b)>0;
}

【深入理解C++】函数模板和类模板的特例化

非模板函数-普通函数

//template<> //没有这个template定义的就是普通函数
bool compare(const char *a,const char *b)
{
	return a<b;
}

注意:模板代码是不能在一个文件中定义,在另外一个文件中使用的。模板代码调用之前,一定要看到模板定义的地方,这样模板才能够正常的实例化,产生能够被编译器编译的代码。所以,一般模板代码都是放在头文件中的。
不过如果是跨文件调用的话,在该函数模板定义的文件中,告诉编译器进行指定类型的模板实例化也是可以的(这种一般不推荐,要手动初始化多个类型的模板函数)。

类模板

类模板与函数模板的定义和使用类似,存在多个类,其功能是相同的,仅仅是数据类型不同,就可以通过类模板复用代码:

template    <类型形式参数表>
  类声明

以下是基于类模板模拟实现了一个栈,支持入栈、出栈、判断栈满、判断栈空、查看栈顶原始,扩容;实现了支持深拷贝的拷贝构造函数和赋值构造函数。

template <typename T>
class SeqStack //模板名称+类型参数列表=类名称
{
public:
	//构造和析构函数不用加<T>(在类里面,就是类模板)
	//但是其他出现模板的地方都加上类型参数列表
	SeqStack(int size=10)
		:_pstack(new T[size])
		,_top(0)
		,_size(size)
	{}
	
	~SeqStack()
	{
		delete []_stack;
		_pstack=nullptr;
	}
	
	SeqStack(const SeqStack<T> &stack) //重载拷贝构造运算符
		:_top(stack._top)
		,_size(stack._size)
	{
		_pstack=new T[_size];
		//memcopy是浅拷贝,一般仅用于一些内置类型,对于对象等一般for循环赋值
		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) //入栈操作
	{
		if (full())
			expand();
		_pstack[_top++]=val;
	}
	void pop()
	{
		if(empty())
			return;
		--top;
	}
	T top() const
	{
		if (empty())
			throw "stack is empty"; //抛出异常
		return _pstack[_top-1];
	}
	
	bool full() const {return _top==_size;}
	bool 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;
	}
	
}

C++ 类模板(template)详解

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值