您的位置:首页 > 编程语言 > C语言/C++

【c++】模板和模板类

2017-05-05 12:57 190 查看
C++是一种“强类型”语言。也就是说,对于一个变量,编译器必须确切知道它是什么类型。但是,这种强类型函数在实现一些简单函数反而更麻烦。例如:求两大数的较大者,应以Max( )函数,我们需要对不同数据类型分别定义不同重载版本来实现:

int Max(int x,int y)        //比较两个int类型的值
{
return ((x > y) ? x : y);
}
float Max(float x,float y)  //比较两个float类型的值
{
return ((x > y) ? x : y);
}
double Max(double x,double y)  //比较两个double类型的值
{
return ((x > y) ? x : y);
}


我们看到,虽然我们可以通过函数重载去实现,但明显存在一些缺点:

1、所有的函数除返回类型外,函数体都相同,代码复用率低;

2、只要新类型出现,我们就需要添加新的对应函数;

3、维护不方便。

什么是模板?

C++程序有类和函数组成,模板分为类模板和函数模板。模板就是把功能相似,仅数据类型不同的函数或类设计为通用的函数模板或类模板,提供给用户。

模板是“泛型编程”的基础。简单的说,类是对象的抽象,而模板是类的抽象,用模板能定义具体类。

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

template<typename Paraml,typename Paraml,... ,class Paraml>
返回类型 函数名(函数形参表)
{
}


模板定义以关键字template开始,形参由关键字class或typename及其后面的类型名构成,一般建议尽量使用typename。

注意:不能使用struct代替typename。

模板函数也可以定义为inline函数

template<typename T>
inline T Add(const T _left, const T _right)
{
return (_le _right);
}


注意:inline关键字必须放在模板形参表之后,返回值之前,不能放在template之前

例如:前面的Max()函数可以用模板定义如下:

template<typename T>
T Max(T x,T y)
{
return ((x > y) ? x : y);
}


模板是一个蓝图,它本身不是类也不是函数,编译器用模板产生的指定的类或者函数的特定类型版本,产生模板特定类型的过程称为函数模板实例化。

实例:定义一个函数模板,比较两个数大小。

#include<iostream>
using namespace std;
template<typename T>
T Max(T x, T y)
{
return ((x > y) ? x : y);
}
int main()
{
cout << Max(10, 20) << endl;
cout << Max(13.14, 5.2) << endl;
cout << Max(10, (int)5.2) << endl;
cout << Max<int>(10, 5.2) << endl;

}


模板参数 :1,类型参数

2,非类型参数

类型参数可以用来指定返回类型或函数的参数类型,以及在函数体内用于变量的声明或类型的转换:

template<typename T>
T foo(T* p)
{
T tmp = *p;
return tmp;
}


模板形参的名字在同一模板形参列表中只能使用一次。

非类型模板参数 :

一个非类型参数表示一个值而非一个类型。非模板类型形参是模板内部定义的常量,在需要常量表达式的时候,可以使用非模板类型参数。

例如数组长度:


说明:

1、一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例

化为这个非模板函数。

2、对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调动非模板

函数而不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的函数,

那么将选择模板。

3、显式指定一个空的模板实参列表,该语法告诉编译器只有模板才能来匹配这个调用,

而且所有的模板参数都应该根据实参演绎出来。

4、模板函数不允许自动类型转换,但普通函数可以进行自动类型转换。

模板函数特化

特化的一般形式:

1、关键字template后面接一对空的尖括号<>

2、函数名后接模板名和一对尖括号,尖括号中指定这个特化定义的模板形参

3、函数形参表

4、函数体

例如,对于前面的Max()函数模板。

template<class T>
T Max(T x,T y)
{
return ((x>y) ? x:y);
}


如果比较的是两个“const char*”类型,那么函数模板用“const char*”型的模板实参实例化。如果还想让每个实参都被解释为C风格的字符串而不是字符指针,那么饿通过模板定义给出的语义就不正确了,必须为函数模板实例化提供“const char*”的特化:

#include<cstring>     //引入cstring的相关声明
template<>           //特化标志
const char* Max<const char*>(const char* x,const char* y)            //用const char*转化
{
return (strcmp(x,y)<0)?x:y;
}


特化的声明必须与特定的模板相匹配。

由于有了这个特化,程序中对所有用两个“const char*”型形参进行调用的Max()都会调用这个特化的定义,而对于其他的调用,则通过模板定义实例化对象:

const char* a = “hello”;
const char* b = "world";
int x = 10;
int y = 20;
Max(a,b);      //调用模板的特化版本进行实例化
Max(x,y);      //调用模板的通用版本进行实例化


注意:在模板特化版本的调用中,实参类型必须与特化版本函数的形参类型完全匹配,如果不匹配,编译器将为实参模板定义中实例化一个实例。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: