C++中关于模板&泛型编程问题:
问题引入:何编写一个通用加法函数?
(1)使用函数重载,针对每个所需相同行为的不同类型重新实现它
int Add(const int &_iLeft, const int&_iRight)
{
return (_iLeft +_iRight);
}
float Add(const float &_fLeft, constfloat &_fRight)
{
return (_fLeft +_fRight);
}
【缺点】
1、只要有新类型出现,就要重新添加对应函数。
2、除类型外,所有函数的函数体都相同,代码的复用率不高
3、如果函数只是返回值类型不同,函数重载不能解决
4、一个方法有问题,所有的方法都有问题,不好维护。
(2)使用公共基类,将通用的代码放在公共的基础类里面
【缺点】
1、借助公共基类来编写通用代码,将失去类型检查的优点;
2、对于以后实现的许多类,都必须继承自某个特定的基类,代码维护更加困难。
(3)使用特殊的预处理程序
#define ADD(a, b) ((a) + (b))
【缺点】
不是函数,不进行参数类型检测,安全性不高
综上所述的问题,我们需要引入泛型编程,即为需要的函数或者类编写一个模板,在实用的时候实例化即可。那么,什么是泛型编程?什么是模板?
一、 泛型编程
泛型编程:编写与类型无关的逻辑代码,是代码复用的一种手段。模板是泛型编程的基础。
二、 函数模板
函数模板:代表了一个函数家族,该函数与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。
模板函数定义的格式:template<typename T1, teypename T2, ……….typename Tn>
函数返回值 函数名(参数列表)
{
. . . . . .
}
Eg:
template<typename T>
T Add( T left, T right )
{
return left+right;
}
template和typename 为关键字,T为模板形参的名字,可随意命名。
typename是用来定义模板参数关键字,也可以使用class。建议尽量使typename。
实例化:模板是一个蓝图,它本身不是类或者函数,编译器用模板产生指定的类或者函数的特定类型版本,产生模板特定类型的过程称为函数模板实例化
注:模板被编译了两次:
① 实例化之前,检查模板代码本身,查看是否出现语法错误,如:遗漏分号
②在实例化期间,检查模板代码,查看是否所有的调用都有效,如:实例化类型不支持某些函数调用
实参推演:
从函数实参确定模板形参类型和值的过程称为模板实参推断,多个类型形参的实参必须完全匹配
类型形参转换:
一般不会转换实参以匹配已有的实例化,相反会产生新的实例。
编译器只会执行两种转换:
1、const转换:接收const引用或者const指针的函数可以分别用非const对象的引用或者指针来调用
2、数组或函数到指针的转换:如果模板形参不是引用类型,则对数组或函数类型的实参应用常规指针转换。数组实参将当做指向其第一个元素的指针,函数实参当做指向函数类型的指针。
Eg:
template<typename T>
void FunTest1(const T* t)
{
cout<<"FunTest1();"<<*t<<endl;
}
template<typename T>
void FunTest2(const T& t)
{
cout<<"FunTest2();"<<t<<endl;
}
template<typename T>
void FunTest3(T t1, T t2)
{
cout<<"FunTest3()"<<endl;
}
int Add(int a, int b)
{
return a+b;
}
int main()
{
int A = 10;
int* pA = &A;
FunTest1(pA);
int b = 20;
int& pB = b;
FunTest2(pB);
int array1[10];
int array2[20];
FunTest3(array1, array2);
FunTest3(Add,Add);
system("pause");
return 0;