1 模板概述
- 模板是对具有相同特性的函数或类的再抽象,模板是一种参数化的多态性工具。
- 所谓参数化多态性,是指将程序所处理的对象的类型参数化,使一段程序代码可以用于处理多种不同类型的对象。
- 采用模板编程,可以为各种逻辑功能相同而数据类型不同的程序提供一种代码共享的机制。
模板分类
函数模板
类模板
模板的实例化
产生模板的特定类型实例的过程称为 实例化。包括: 类模板的实例化和 函数模板的实例化。
模板通过参数实例化可以构建具体的函数或类,称为模板函数和模板类。
2、函数模板
函数模板作用:建立一个通用函数,其函数返回值类型和形参类型可以不具体制定,用一个虚拟的类型来代表
例1:数据为int或double时的求最大值问题
int Max(int x,int y)
{
if(x>y) return x;
else return y;
}
double Max(double x,double y)
{
if(x>y) return x;
else return y;
}
例2:数据为int或double时的求绝对值问题
int abs(int a)
{
return a<0?-a:a;
}
double abs(double a)
{
return a<0?-a:a;
}
函数模板的定义格式
函数模板是参数化的函数。 定义格式如下:
template <模板形参表>
返回值类型 函数名(参数表)
{
函数体
}
具有求绝对值功能的函数模板的定义
#include<iostream>
using namespace std;
template<typename T> //模板定义,T为模板参数
T abs(T a)
{ //定义函数模板
return a<0?-a:a;
}
void main()
{
int x=-12;
double y=12.5;
cout<<abs(x)<<endl;
cout<<abs(y)<<endl;
}
int abs(int a)
{
return a<0?-a:a;
}
double abs(double a)
{
return a<0?-a:a;
}
具有求最大值功能的函数模板的定义。
#include <iostream.h>
template <class T>
T Max(T x,T y)
{
return (x>y)?x:y;
}
int Max(int x,int y)
{
if(x>y) return x;
else return y;
}
double Max(double x,double y)
{
if(x>y) return x;
else return y;
}
int main()
{
int x1,y1;
float x2,y2;
double x3,y3;
cout<<"请输入2个整型数据,用空格分隔:"<<endl;
cin>>x1>>y1;
cout<<"The max of x1,y1 is:"<<Max(x1,y1)<<endl; //T为int
cout<<"请输入2个实型数据,用空格分隔:"<<endl;
cin>>x2>>y2;
cout<<"The max of x2,y2 is:"<<Max(x2,y2)<<endl; //T为float
cout<<"请输入2个双精度数据,用空格分隔:"<<endl;
cin>>x3>>y3;
cout<<“The max of x3,y3 is:”<<Max(x3,y3)<<endl; //T为 double
return 0;
}
注意说明
#include <iostream.h>
template
T Max(T x, T y) //定义函数模板
{
return (x>y) ?x: y;
}
自动类型推导,必须推导出一致的数据类型T才可以使用
模板必须要确定出T的数据类型才可以使用
template是模板定义的关键字。
<模板形参表>中包含一个或多个用逗号分开的模板形式参数,每一项均由关键字class或typename引导一个由用户命名的标识符,此标识符为模板参数(用来进行类型传递),模板参数表示一种数据类型,可以是基本数据类型或类类型。该数据类型在发生实际函数调用时将被实例化,即用调用处的实际数据类型替代它。
利用具体化的模板,可以解决自定义类型的通用化
学习模板并不是为了写模板,而是在STL能够运用系统提供的模板
3、类模板
- 如同函数模板一样,类模板是参数化的类,即用于实现数据类型参数化的类。
- 应用类模板可以使类中的数据成员、成员函数的参数及成员函数的返回值能根据模板参数匹配情况取任意数据类型。
- 这种类型既可以是C++预定义的数据类型,也可以是用户自定义的数据类型。
为什么要引入类模板?
1、定义一个矩形类,边长是整数,该类封装计算边长、面积等函数
2、定义一个矩形类,边长是实数,该类封装计算边长、面积等函数
抽象数据类型长方形的定义
int类型:
class Rectangle
{
private:
int length,width;
public:
Rectangle(int l, int w );
~Rectangle( );
int getLength( );
int getWidth( );
int circumference( );
int area( );
};
double类型:
class Rectangle
{
private:
double length,width;
public:
Rectangle(double l, double w );
~Rectangle( );
double getLength( );
double getWidth( );
double circumference( );
double area( );
};
类模板的定义格式
template <模板形参表>
class 类模板名
{
成员的声明;
}
#include <iostream>
using namespace std;
template <typename T> //typename或class
class Square //类模板定义
{
T x;
public:
Square(T xx):x(xx){ }
T fun(){return x*x;}
};
类模板成员函数的定义
类模板中的成员函数的定义,若放在类模板的定义之中,则与类的成员函数的定义方法相同;若在类模板之外定义,则成员函数的定义格式如下:
template<模板形参表>
返回值类型 类模板名<形参名表>::成员函数名(参数表)
{
成员函数体
}
类模板对象做函数参数
1、指定传入的类型:直接显示对象的数据类型
2、参数模板化:将对象中的参数变为模板进行传递
3、整个类模板化:将这个对象类型模板化进行传递
类模板与函数模板的区别
类模板与函数模板区别主要有两点:
- 类模板没有自动类型推导的使用方式
- 类模板在模板参数列表中可以有默认参数
类模板与继承
当类模板碰到继承时,需要注意以下几点:
当子类继承的父类是一个类模板时,子类在声明的时候,要指定出父类中T的类型
如果不指定,编译器无法给子类分配内存
如果想灵活指定出父类中T的类型,子类也需为类模板
例:计算各种类型的面积
#include <iostream>
using namespace std;
template <typename T> //typename或class
class Square
{ //类模板定义
T x;
public:
Square(T xx):x(xx){}
T fun(){return x*x;}
};
class Rectangle
{
private:
int length,width;
public:
Rectangle(int l, int w );
~Rectangle( );
int getLength( );
int getWidth( );
int circumference( );
int area( );
};
template <typename T>
class Rectangle
{
private:
T length,width;
public:
Rectangle(T l, T w );
~Rectangle( );
T getLength( );
T getWidth( );
T circumference( );
T area( );
};
int main()
{
Square <int> inta(15); //类的实例化
Square <float> floata(16.5);
Square <double> doublea(15.55);
cout<<"square of int data:"<<inta.fun()<<endl;
cout<<"square of float data:"<<floata.fun()<<endl;
cout<<"square of double data:"<<doublea.fun()<<endl;
};