模板定义
模板是实现代码重用机制的一种工具,可以实现类型参数化(把类型定义为参数)
从而实现真正的代码重用性,有两种模板,一种是函数模板,一种是类模板
函数模板
在c++中也存在泛型变成的理念(不考虑具体数据类型的变成方式)
之前我写过一篇unity中c#的使用泛型的方法 大家有兴趣可以去自己查看
就用交换两个值的为例子 假如说我们要交换两个值
我们可能只会每种类型都写一种
void Swap(int a, int b)//int类型
{
int tmp = a;
a = b;
b = tmp;
}
void Swap(double a, double b)//double类型
{
double tmp = a;
a = b;
b = tmp;
}
这样是很有局限性的 我们可以使用函数模板实现代码复用的效果
template <typename T>
void Swap(T& a, T& b)
{
T tmp = a;
a = b;
b = tmp;
}
然后我们测试一下
template <typename T>
void Swap(T& a, T& b)
{
T tmp = a;
a = b;
b = tmp;
}
void main()
{
string a = "12345";
string b = "54321";
Swap(a, b);
cout << "a:" << a << endl;
cout << "b:" << b << endl;
}
我们需要注意 函数模板是不允许隐式类型转换的
template <typename T1, typename T2, typename T3>
T1 add(T2 a, T3 b)
{
T1 ret;
ret = static_cast<T1>(a + b);
return ret;
}
void main()
{
int c = 12;
float d = 23.4;
cout << add<float>(c, d) << endl; //返回值在第一个类型参数中指定
cout << add<int, int, float>(c, d) << endl;
system("pause");
}
可以看到两种输出类型是不一样的
再就是我们测试一下几种函数的调用先后顺序
template <typename T>
void fun(T a)
{
cout << "void fun(T1 a)" << endl;
}
template <typename T1, typename T2>
void fun(T1 a, T2 b)
{
cout << "void fun(T1 a, T2 b)" << endl;
}
void fun(int a, float b)
{
cout << "void fun(int a, float b)" << endl;
}
void main()
{
int a = 0;
float b = 0.0;
fun(a);
fun(a, b); //普通函数void fun(int a, float b)已经能完美匹配,于是调用普通函数
fun(b, a); //这个调用,函数模板有更好的匹配,于是调用函数模板
fun<>(a, b); //限定只使用函数模板
}
然后看运行结果
函数模板特化
注意函数模板特化只有全特化,没有偏特化
//普通模板
template<class T1, class T2>
bool Compare(T1 a, T2 b)
{
cout << "普通模板" << endl;
return a == b;
}
//函数模板特化
template<>
bool Compare(const char* a, const char* b)
{
cout << "函数模板特化" << endl;
return strcmp(a, b) == 0;
}
类模板
template <类型形式参数>
class 类名
{
//类声明体;
};
template <类型形式参数>
返回类型 类名 <类型> :: 成员函数名1(形式参数)
{
//成员函数定义体;
}
... ...
template <类型形式参数>
返回类型 类名 <类型> :: 函数名N(形式参数)
{
//成员函数定义体;
}
//例子
template<class T1, class T2>
class Test
{
public:
Test(T1 a, T2 b) :_a(a), _b(b)
{
cout << "模板化" << endl;
}
private:
T1 _a;
T2 _b;
};
类模板全特化
这个知识有点重要,我在面试题中见过面试官问这个
所谓模板全特化就是限定死模板实现的具体类型
//模板全特化
template<>
class Test<int,int>
{
public:
Test(int a, int b) :_a(a), _b(b)
{
cout << "模板全特化" << endl;
}
private:
int _a;
int _b;
};
模板偏特化
偏特化我们可以和特化来比较记忆
模板全特化是限定死所有的实现类型,而模板片特化是只限定一部分实现类型
//模板偏特化
template<class T>
class Test<int,T>
{
public:
Test(int a, T b) :_a(a), _b(b)
{
cout << "模板偏特化" << endl;
}
private:
int _a;
T _b;
};
总结
1.函数模板只有全特化,没有偏特化
2.模板,模板的特化,模板的偏特化都存在的情况下,编译器在编译阶段进行匹配,优先特殊的
3.函数模板不能是虚函数,因为每个包含虚函数的类具有一个虚函数表,包含所有虚函数的地址,因此虚函数大小确定
模板只有被使用的时候才能实例化,将其声明为虚函数会使虚函数表的大小不确定,所以成员函数模板不能为虚函数