一、概述
泛型(Generic Programming)即是指具有在多种数据类型上皆可操作的含
意。所谓泛型编程,实际上是建立一个通用函数,其函数类型和形参类型不具体指定,用一个虚拟的类型来代表。这个通用函数就称为函数模板。上面所叙述的是函数模板,实际上模板分为函数模板和类模板。类模板与函数模板的定义和使用类似,有时,有两个或多个类,其功能是相同的,仅仅是数据类型不同,所以将类中的类型进行泛化。
二、模板的形式
1、函数模板语法格式
template<typenam T>
template<class T>
-------------------------------------
template<typename 类型参数表>
返回类型 函数模板名(函数参数列表)
{
函数模板定义体
}
2、类模板的语法格式
template<typename T>
class A{}
template是语义是模板的意思,尖括号中先写关键字 typename 或是
class ,后 面跟一个类型 T,此类即是虚拟的类型。至于为什么用 T,用的人多了,也就是 T 了。
三、函数模板细化和模板案例
1、模板函数小案例
#include <iostream>
using namespace std;
template<typename T>
void swap(T &a, T &b)
{
T t = a;
a = b;
b = t;
}
int main()
{
int x = 10;
int y = 20;
cout << "int型交换前" << endl;
cout << "x=" << x << "y=" << y << endl;
swap<int>(x, y);
cout << "int型交换后" << endl;
cout << "x=" << x << "y=" << y << endl;
float e = 1.1;
float f = 2.2;
cout << "float类型交换前" << endl;
cout << "e=" << e << "f=" << f << endl;
swap <float>(e, f);
cout << "float类型交换后" << endl;
cout << "e=" << e << "f=" << f << endl;
return 0;
}
总结:函数模板,只适用于函数的参数个数相同而类型不同,且函数体相同的情况。如果个数不同,则不能用函数模板
2、函数模板与函数重载
#include <iostream>
using namespace std;
template <typename T>
void swap(T &a, T &b)
{
cout << "我是模板函数" << endl;
T t = a;
a = b;
b = t;
}
void swap(char &a, int &b)
{
cout << "我是普通函数" << endl;
int t = a;
a = b;
b = t;
}
int main()
{
char cData = "a";
int iDate = 10;
swap(cData, iDate);
swap(iDate, cData);
swap<int>(iDate, cData);
return 0;
}
总结:普通函数会进行隐士的数据类型转换, 函数模板不提供隐式的数据类型转换必须是严格的匹配。当函数模板和普通函数都符合调⽤用时,优先选择普通函数,若显⽰示使⽤用函数模板,则使⽤用<>类型列表。如果
函数模板产⽣生更好的匹配使⽤用函数模板。
3、模板编译机制总结
- 编译器并不是把函数模板处理成能够处理任意类的函数
- 编译器从函数模板通过具体类型产生不同的函数
- 编译器会对函数模板进行两次编译,在声明的地方对模板代码本身进行编译;在调用的地方对参数替换后的代码进行编译。
四、类模板细化和模板案例
1、一个简单的类模板小案例
#include <iostream>
using namespace std;
template<typename T>
//template<class T>
class A
{
public:
A(T tt)
{
this->t = tt;
}
T &getT()
{
return t;
}
private:
T t;
};
int main(void)
{
A<int> a(100);
cout << a.getT() << endl;
return 0;
}
总结:在类模板前应该用template<typename T>
或者template<class T>
来声明。
2、模板类的派生
#include <iostream>
using namespace std;
template<typename T>
class A
{
public:
A(T tt)
{
this->t = tt;
}
private:
T t;
};
//模板类派生普通类
class B : public A<int>
{
public:
B(int t, int ii) : A<int> a
{
this->ii = i;
}
void printB()
{
cout<< "i:" << i <<endl;
}
private:
int i;
}
//模板类派生模板类
template <class T>
class C : public A<T>
{
public:
C(T jj, T t) : A<T> t
{
this->jj = j;
}
void printC()
{
cout << "j:" << j <<endl;
}
private:
T j;
};
总结:子类从模板类继承的时候,需要让编译器知道⽗父类的数据类型具体是什么(数据类型的本质:固定⼤大⼩小内存块的别名)A<int>