关键词:模版
C++提供两种模板机制:函数模板、类模板,使得程序(算法)可以从逻辑功能上抽象,把被处理的对象(数据)类型作为参数传递。
模板把函数或类要处理的数据类型参数化,表现为参数的多态性,称为类属。模板用于表达逻辑结构相同,但具体数据元素类型不同的数据对象的通用行为。
函数模板(function template)
所谓函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体指定,用一个虚拟的类型来代表。凡是函数体相同的函数都可以用这个模板来代替,不必定义多个函数,只需在模板中定义一次即可。在调用函数时系统会根据实参的类型来取代模板中的虚拟类型,从而实现了不同函数的功能。
template <typename T> //模版,固定形式,不加“;”
T add(T x, T y) //函数模版
{
return x + y;
}
template <typename T1, typename T2> //模版可定义多种类型
void print(T1 x,T2 y)
{
cout << "template <typename T1, typename T2>" << endl;
cout << x << " " << y << endl;
}
/*****************************************************************/
//main.cpp
int main()
{
int a = 1, b = 2;
double c = 2.2, d = 3.3;
cout << add(a, b) << endl; //函数模版,隐式调用,函数根据参数类型调用模版
cout << add(c, d) << endl;
cout << add<int>(a, b) << endl; //显式调用
//cout << add<int>(a, c) << endl; //两个参数类型不一致时,一定要显式调用
print(a, c); //隐式调用,当函数模版遇到同名的普通函数,优先调用普通函数
print<int , double>(a, c); //显示调用则调用的是函数模版
//普通函数存在默认的类型转换(int和char),函数模版不行
print(a, b, c); //函数模版也和普通函数一样可以重载
system("pause");
return 0;
}
几个注意点:
- 普通函数存在默认的类型转换(int和char),函数模版不行
- 两个参数类型不一致时,一定要显式调用
- 隐式调用,当函数模版遇到同名的普通函数,优先调用普通函数
- 编译器并不是把函数模板处理成能够处理任意类的函数,编译器从函数模板通过具体类型产生不同的函数,会对函数模板进行两次编译,在声明的地方对模板代码本身进行编译,在调用的地方对参数替换后的代码进行编译。
类模板
类模板用于实现类所需数据的类型参数化 ,类模板在表示如数组、表、图等数据结构显得特别重要,这些数据结构的表示和算法不受所包含的元素类型的影响
template <typename T>
class A
{
protected:
T m_a;
public:
A(T a);
};
template <typename T>
A<T>::A(T a)
{
m_a = a;
}
class B : public A<int> //模板类派生普通类
{
private:
int m_b;
public:
B(int b);
};
template <typename T, typename T2>
class C : public A<T2> // 模板类派生模板类
{
private:
T m_c;
public:
C(T c, T2 a);
void print();
};
template <typename T, typename T2>
C<T, T2>::C(T c, T2 a) : A<T2>(a)
{
m_c = c;
}
int main()
{
B b(1);
C<int, double> c(1, 1.00); //模板类一定要显式调用
return 0;
}
以上代码是单个类模板的语法
类模板一定要显式调用 ,不然编译会报错
类模板的几个重要事项
用友元函数重载 << >>
friend ostream& operator<< <T> (ostream &out, Complex<T> &c3) ;
友元函数:友元函数不是实现函数重载(非 << >>)
1)需要在类前增加 类的前置声明 函数的前置声明
template<typename T>
class Complex;
template<typename T>
Complex<T> mySub(Complex<T> &c1, Complex<T> &c2);
2)类的内部声明 必须写成:
friend Complex<T> mySub <T> (Complex<T> &c1, Complex<T> &c2);
3)友元函数实现 必须写成:
template<typename T>
Complex<T> mySub(Complex<T> &c1, Complex<T> &c2)
{
Complex<T> tmp(c1.a - c2.a, c1.b-c2.b);
return tmp;
}
4)友元函数调用 必须写成
Complex<int> c4 = mySub<int>(c1, c2);
cout<<c4;
结论:友元函数最好只用来进行 左移 友移操作符重载。
类模板中的static:
- 从类模板实例化的每个模板类有自己的类模板数据成员,该模板类的所有对象共享一个static数据成员
- 和非模板类的static数据成员一样,模板类的static数据成员也应该在文件范围定义和初始化
- 每个模板类有自己的类模板的static数据成员副本