实用经验 92 区分函数模版与模版函数,类模版和模板类

模板就是实现代码重用机制的一种工具,它可实现类型参数化,即把类型定义为参数, 从而实现了代码的可重用性。模版可以分为两类,一个是函数模版,另外一个是类模版。在使用模板概念时,经常会遇到这4个概念:函数模板,模板函数,类模板,模板类。这4个概念非常类似,也经常被我们所误用,本使用经验将主要讲述他们的差异。

这4个概念从汉语语法的角度考虑仅是语序的差异。对于函数模板和模板函数,函数模板应该强调的是模板,而模板函数应该强调的是函数。而对于类模板和模板类,类模板强调的应该是类的模板,而模板类强调的应该是一个类。

函数模板和模板函数

函数模板重点强调模板,函数仅仅是一个修饰词。所以函数模板指用于产生实例函数的模板。而模板函数重点在函数,模板是一个修饰词。所有模板函数应该是模板所生成的函数。函数模板特例化而生成的函数就是模板函数。

函数模板的一般定义形式如下:

template <classtypename T>
返回类型 函数名(形参表)
{
	//函数定义体 
}

说明

  • template为声明模板的关键字,声明模板形参的关键字class或typename也不能省略,如果类型形不只一个 ,每个类型形参前都要加class, 类型形参表可包含基本数据类型可包含类类型。
  • 在函数模板被调用时,编译器根据实际参数的类型确定模板参数T的类型,并自动生成一个对应的函数,即模板函数。模板参数的类型不同,生成的模板函数也不同。
  • 模板函数类似于重载函数,但两者还是有很大差异:函数重载时,每个函数体内可以执行不同的动作,但同一个函数模板实例化后的模板函数都必须执行相同的动作。

模板函数是由函数模板实例化生产的具体函数,上述函数模板生成的模板函数的一般形式为:

返回类型 函数名<数据类型参数标识符>(形参表)
{
	//函数定义体 
}

下面是一例,函数模板的定义和使用的例子:

#include <iostream.h> 

// 定义绝对值求值函数模板
template <class T>  
T abs(T val)
{
	return (val<0) ? -val : val; 
} 

int main() 
{ 
	int i = 100; 
	cout << abs(i)<< endl; //类型参数T替换为int 
	long l = -12345L; 
	cout << abs(l) << endl; //类型参数T替换为long 
	float f = -125.78F; 
	cout << abs(f) << endl; //类型参数T替换为float
	return 0;
}

不仅如此,函数模板亦可使用多个类型参数,每个类型参数前面均需加关键字class或typename,其间用逗分隔,其形式如下所示:

template <class T1, class T2, class T3>

下面是一例,使用多类型参数的函数模板:

#include <iostream.h> 

// 求最大值函数模板
template <class T1,class T2>
T1 Max(T1 x, T2 y) 
{ 
	return x>y ? x: (T1)y; 
} 

int main() 
{ 
	int i = 100;
	float f = -125.78F;
	cout << Max(i,f) << endl;  //类型参数T1替换为int,T2替换为float 
	return 0;
} 

类模板和模板类

类模板和模板类的关系与函数模板和模板函数类似。类模板强调模板,由此类模板生成的具体类,称之为模板类。类模板的定义如下:

template <classtypename T>
class 类名
{
	// 类定义......
};

说明

  • template是声明各模板的关键字,表示声明一个模板,模板参数可以是一个,也可以是多个。
  • 在类中凡是采用标准数据类型的数据成员,函数成员的参数都必须加上类型标识符;返回类型也是如此。
  • 如果类的成员函数在类声明之外定义,则类的成员函数声明必须是函数模板形式,其定义形式如:template <class T> 返回类型 类名::函数名(T 形参1,……)。

将类模板实例化后生成的具体类是模板类。模板类的一般形式为:

类名<T> 对象1, 对象2,, 对象n;

下面是一个堆栈模板类:

//  堆栈模板类
template <class T>
class Stack
{
public:
	Stack()
	{ 
		m_nPos= 0;
	}
	virtual ~Stack() 
	{}
	// 压栈函数
	void Push(T value);
	// 出栈函数
	T Pop(); 
	// 判断堆栈是否为空
	bool IsEmpty()
	{
		return m_nPos == 0;
	}
	// 判断堆栈是否还有元素存在
	bool HasElement()
	{
		return !IsEmpty();
	}
	// 判断堆栈是否已满了。
	bool IsFull()
	{
		return m_nPos == STATCK_SIZE;
	}
private:
    const static int STATCK_SIZE = 100;
	//使用常量表示堆栈的大小
	int m_nPos; 
	// 堆栈数据缓存区。
	T m_Data[STATCK_SIZE];
};

// 压栈函数
template <class T>
void Stack<T>::Push(T value)
{
	//使用后置递增操作符
	m_Data[m_nPos++] = value;
}
// 出栈函数
template <class T>
T Stack<T>::Pop()
{
	//使用前置递减操作符
	return m_Data[--m_nPos];
}

根据以上的分析,我们可等到这样的结论:类模板和函数模板都是实例化之前的工具,模板类和模板函数都是实例化的产物。

请谨记

  • 掌握类模板和模板类及函数模板和模板函数的差异,首先你需要明白各自强调的重点。
  • 类模板和函数模板强调模板。模板类和模板函数强调具体类和函数。
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值