1、函数模板
//普通函数
void myPrint(int a, int b)
{
cout << "普通函数" << endl;
cout << "a = " << a << ", b = " << b << endl;
}
/*
模板函数:可以写成下面两种方式
template<typename T>
template<class T>
*/
template<typename T>//只对下面的第一个函数有用
void myPrint(T a, T b)
{
cout << "模板函数" << endl;
cout << "a = " << a << ", b = " << b << endl;
}
int main(void)
{
int aInt = 10;
int bInt = 20;
char aChar = 'a';
char bChar = 'b';
myPrint(aInt, bInt);//调用普通函数
cout << " ----- " << endl;
myPrint(aChar, bChar);//调用模板函数
cout << " ------ " << endl;
myPrint(aChar, bInt);//调用普通函数
cout << " ------ " << endl;
myPrint<int>(aInt, bChar);//调用模板函数
return 0;
}
结论:
1.1 当函数模板和普通函数都符合调用时,优先选择普通函数。
1.2 如果函数模板产生更好的匹配 使用函数模板。
1.3 普通函数会进行隐士的数据类型转换, 函数模板不提供隐式的数据类型转换 必须是严格的匹配。
1.4 当普通函数需要隐式转换的时候,如果模板函数能够匹配,那么就优先使用模板函数。
1.5 若显示使用函数模板,则使用<> 类型列表。
1.6 编译器并不是把函数模板处理成能够处理任意类类型的函数,而是通过具体类型产生不同的函数,
编译器会对函数模板进行两次编译,在声明的地方对模板代码本身进行编译;在调用的地方对参数替换后的代码进行编译。
2、类模板
template<class T>
class A
{
public:
A(T a)
{
this->a = a;
}
void printA()
{
cout << "a = " << a << endl;
}
private:
T a;
};
//继承模板类, 直接继承已经实例化的模板类
//这么继承完的B类, B类此时是一个普通类。
class B :public A<int>
{
public:
B(int a, int b) : A<int>(a)
{
this->b = b;
}
void printB()
{
cout << "b = " << b << endl;
}
private:
int b;
};
//C类继承的是一个模板类,没有实例化,此时C类依然是一个模板类,
//编译器在对c类处理依然需要二次编译
template <class T>
class C :public A<T>
{
public:
C(T a, T c) : A(a)
{
this->c = c;
}
void printC()
{
cout << "c = " << c << endl;
}
private:
T c;
};
//普通函数
void func(A<int> & a)
{
a.printA();
}
//模板函数
template <class T>
void func2(A<T> &a)
{
a.printA();
}
int main(void)
{
A<int> a(10);//在定义一个对象的时候,要明确此类所泛化的具体类型
a.printA();
func(a);
func2<int>(a);
A<double> a2(30.0);
a2.printA();
cout << " ------ " << endl;
B b(100, 200);
b.printB();
cout << "-------- " << endl;
C<int> c(1000, 2000); //C类是一个模板类
c.printC();
return 0;
}
结论:
2.1 模板类不要轻易使用友元函数。
2.2 实现模板方法建议在同一个文件.h中完成,这里引入hpp文件,意思是.cpp和.h的结合。
2.3 模板类中的static成员:同种数据类型的static成员是共享的。
假设 a1,a2,a3 是属于A<int>家族的他们共享A<int>::s_value; b1, b2, b3 是属于A<char>家族的他们共享A<char>::s_value;