一、函数模板
1、问题引入
很多C/C++初学者们在刷各种笔试题或者看项目工程代码的时候,或多或少遇到过下面这样的问题。就是为什么一个函数调用时,能够在函数中间加上一个尖括号<>,到底是干嘛用的?
当然可能是会有以下的一些困扰,所以去去思考如何去优化函数重载时重复类型的代码:
void _swap(int &a,int &b) //定义函数的时候不能直接使用swap 这个名字是 标准C++库的接口
{
a = a+b;b=a-b;a=a-b;
}
void _swap(double &a,double &b)
{
a = a+b;b=a-b;a=a-b;
}
void _swap(char &a,char &b)
{
a = a+b;b=a-b;a=a-b;
}
函数的重载可以实现一个函数名多用,将实现相同的或类似功能的函数用一个函数名来定义。这种使用在程序中仍然需要定义每一个函数,用不同的形参类型来实现多态。那么,如何实现只需要定义一个函数,能够适应不同类型的形参实现多态呢??使用函数模板
2、概念
所谓的函数模板[拼音:mú bǎn],实际上就是建立一个通用函数,其函数返回值类型和形参类型不具体指定, 用一个虚拟的类型来代表。这个通用函数就称为函数模版 。
模板是泛型编程的基础,泛型编程即以一种独立于任何特定类型的方式编写代码。
template<typename T>
void _swap(T &a, T &b) //注意:函数名不要使用swap ,这是系统接口
{
cout<<T swap<<endl;
a = a+b;b=a-b;a=a-b;
}
3、函数模板格式
template<typename T> 或 template<class T>
T 模板函数名(T a)
{
}
T 是函数所使用的数据类型的占位符名称,这个名称可以在函数定义中使用。
class和typename的作用相同,都是表示“类型名”,二者可以互换。
在建立函数模版时,只要将第一个函数用虚拟的类型名T代替具体的数据类型。在对程序进行编译时,遇到模版函数的调用,编译系统会将函数名与模版相匹配,将实参的类型取代函数模版中的虚拟类型T
每一个函数模板都要定义自己的虚拟模板类型,不同函数的虚拟模板类型可以一样,但是不是能省略
template<typename T>
T show(T a){cout<<a<<endl;}
template<typename T> //此处不能省略
T print(T a){cout<<a<<endl;}
模板参数必须全部确定为具体类型才能生成模板函数,可以设置默认数据类型参数
template<typename T,typename Ty=int>
void print(T a)
{
cout<<a<<endl;
}
调用的时候可以显式指定数据类型
print<int>(10);
4、例子
#include<iostream> //表示下面这个函数时一个通用函数(函数模板),并且声明T 是一个虚拟的数据类型 int、double、char template <typename T> void swapFunc(T &ra, T &rb) { ra = ra + rb; rb = ra - rb; ra = ra - rb; } template <typename T1, typename T2> void func1(T1 &ra, T2 &rb) { (void)ra; (void)rb; std::cout<<"func(T1 &ra, T2 &rb)"<<std::endl; } int main(int argc, char **argv) { int num1 = 20; int num2 = 30; std::cout<<"函数模板"<<std::endl; std::cout<<"num="<<num1<<"\tnum2="<<num2<<std::endl; swapFunc<int>(num1, num2); //<int>指明 template <typename T>中的T在此处是int类型 std::cout<<"num="<<num1<<"\tnum2="<<num2<<std::endl; int num3 = 10; double num4 = 20.1; func1<int,double>(num3, num4); return 0; }
二、类模板
1、问题引入
现在要实现两个数的一系列运算,比如比较大小
//浮点型比较类
class CompareA{
public:
CompareA(double a,double b):x(a),y(b){}
double max(){return x>y?x:y;}
double min(){return x<y?x:y;}
private:
double x,y;
};
//整型比较类
class CompareB{
public:
CompareB(int a,int b):x(a),y(b){}
int max(){return x>y?x:y;}
int min(){return x<y?x:y;}
private:
int x,y;
};
上面两个类除了数据类型不一样,其他功能都一样,此时可以使用类模板简化成同一个类。
#include <iostream>
using namespace std;
//类模板
template<class T=int>
class Compare{
public:
Compare(T a,T b):x(a),y(b){}
T max();//{return x>y?x:y;} //类内声明
T min(){return x<y?x:y;}
private:
T x,y;
};
//类外定义,T的默认参数不需要加
template<class T>
T Compare<T>::max()
{
return x>y?x:y;
}
int main()
{
//调用的时候显示指定具体的数据类型
Compare<double> mya(10,200);
//如果是使用默认的,那么<>括号也不能省略,里面可以为空
//Compare<> mya(10,200);
cout<<mya.max()<<endl;
cout<<mya.min()<<endl;
return 0;
}
2、格式
template<class T>
class 类名{
};
总结:T表示的是数据类型
3、模板类继承
#include <iostream>
using namespace std;
//模板类--基类
template<class T>
class Base{
public:
Base(T n):baseA(n){}
private:
T baseA;
};
//设计一个子类Child 继承模板类Base<T> -->子类Child也是模板类
template<class T>
class Child:public Base<T>{
public:
Child(T n):Base<T>(n){}
private:
T childA;
};
//设计一个子类Data 继承模板类Base<T> -->子类Data是具体类
class Data:public Base<int>{
public:
Data(int n):Base<int>(n){}
private:
int DataA;
};
int main()
{
Child<int> mya(10);
Data myb(10);
return 0;
}