类模板
类模板是通用类的描述,使用任意类型(泛型)来描述类的定义。
使用类模板的时候,指定具体的数据类型,让编译器生成该类型的类定义。
注意:函数模板中可以不指定具体数据类型,让编译器自动推到,但是类模板不可以。
注意:模板编程不支持分离式编译,即模板类/模板函数的声明与定义应该放在头文件里,否则会在链接时报错;
template <class T>
class 类模板名
{
类的定义;
};
注意
1)在创建对象的时候,
必须指明具体的数据类型。
2)使用类模板时,
数据类型必须适应类模板中的代码。
3)类模板可以为通用数据类型指定缺省的数据类型(C++11标准的函数模板也可以)。
4)模板类的成员函数可以在类外实现。
5)
可以用new创建模板类对象。
6)在程序中,模板类的成员函数使用了才会创建。
下面给出示例
#include <iostream> // 包含头文件。
using namespace std; // 指定缺省的命名空间。
template <class T1, class T2 = string>
class AA
{
public:
T1 m_a; // 通用类型用于成员变量。
T2 m_b; // 通用类型用于成员变量。
AA() {} // 默认构造函数
// 通用类型用于成员函数的参数。
AA(T1 a, T2 b) :m_a(a), m_b(b) { }
// 通用类型用于成员函数的返回值。
T1 geta() // 获取成员m_a的值。
{
T1 a = 2; // 通用类型用于成员函数的代码中。
return m_a + a;
}
T2 getb(); // 获取成员m_b的值。
};
template <class T1, class T2>
T2 AA<T1, T2>::getb() // 获取成员m_b的值。
{
return m_b;
}
int main()
{
AA<int, string>* a = new AA<int, string>(3, "西施"); // 用模板类AA创建对象a。
cout << "a->geta()=" << a->geta() << endl;
cout << "a->getb()=" << a->getb() << endl;
delete a;
return 0;
}
类模板全特化和部分特化
模板类具体化(特化、特例化)有两种:
完全具体化和部分具体化。
具体化程度高的类优先于具体化程度低的类,具体化的类优先于没有具体化的类。
具体化的模板类,成员函数类外实现的代码应该放在源文件中。
下面给出示例
#include <iostream>
using namespace std;
// 类模板
template<class T1, class T2>
class AA {
public:
T1 m_x;
T2 m_y;
AA(const T1 x, const T2 y) :m_x(x), m_y(y) { cout << "类模板:构造函数。\n"; }
void show() const;
};
template<class T1, class T2>
void AA<T1, T2>::show() const
{
cout << "类模板:x = " << m_x << ", y = " << m_y << endl;
}
// 类模板特化
template<>
class AA<int, string> {
public:
int m_x;
string m_y;
AA(const int x, const string y) :m_x(x), m_y(y) { cout << "完全具体化:构造函数。\n"; }
void show() const;
};
void AA<int, string>::show() const
{
cout << "完全具体化:x = " << m_x << ", y = " << m_y << endl;
}
// 类模板部分特化
template<class T1>
class AA<T1, string> {
public:
T1 m_x;
string m_y;
AA(const T1 x, const string y) :m_x(x), m_y(y) { cout << "部分具体化:构造函数。\n"; }
void show() const;
};
template<class T1>
void AA<T1, string>::show() const
{
cout << "部分具体化:x = " << m_x << ", y = " << m_y << endl;
}
int main()
{
// 具体化程度高的类优先于具体化程度低的类,具体化的类优先于没有具体化的类。
AA<int, string> aa1(8, "张三"); // 将使用完全具体化的类。
AA<char, string> aa2(8, "李四"); // 将使用部分具体化的类。
AA<int, double> aa3(8, 9666); // 将使用模板类。
}
模板类于继承
1)模板类继承普通类(常见)。
2)普通类继承模板类的实例化版本。
3)
普通类继承模板类。(常见)
4)模板类继承模板类。
5)模板类继承模板参数给出的基类(不能是模板类)。
下面主要讲普通类继承模板类
#include <iostream>
using namespace std;
template<class T1, class T2>
class BB
{
public:
T1 m_x;
T2 m_y;
BB(const T1 x, const T2 y) : m_x(x), m_y(y) { cout << "调用了BB的构造函数。\n"; }
void func2() const { cout << "调用了func2()函数:x = " << m_x << ", y = " << m_y << endl; }
};
template<class T1, class T2>
class AA:public BB<T1,T2> // 普通类AA变成了模板类,才能继承模板类。
{
public:
int m_a;
AA(int a, const T1 x, const T2 y) : BB<T1,T2>(x,y),m_a(a) { cout << "调用了AA的构造函数。\n"; }
void func1() { cout << "调用了func1()函数:m_a=" << m_a << endl;; }
};
int main()
{
AA<int,string> aa(3,8, "我是一只傻傻鸟。");
aa.func1();
aa.func2();
return 0;
}
模板类继承模板类
#include <iostream> // 包含头文件。
using namespace std; // 指定缺省的命名空间。
template<class T1, class T2>
class BB // 模板类BB。
{
public:
T1 m_x;
T2 m_y;
BB(const T1 x, const T2 y) : m_x(x), m_y(y) { cout << "调用了BB的构造函数。\n"; }
void func2() const { cout << "调用了func2()函数:x = " << m_x << ", y = " << m_y << endl; }
};
template<class T1, class T2>
class AA:public BB<T1,T2> // 普通类AA变成了模板类,才能继承模板类。
{
public:
int m_a;
AA(int a, const T1 x, const T2 y) : BB<T1,T2>(x,y),m_a(a) { cout << "调用了AA的构造函数。\n"; }
void func1() { cout << "调用了func1()函数:m_a=" << m_a << endl;; }
};
template<class T, class T1, class T2>
class CC :public BB<T1, T2> // 模板类继承模板类。
{
public:
T m_a;
CC(const T a, const T1 x, const T2 y) : BB<T1, T2>(x, y), m_a(a) { cout << "调用了CC的构造函数。\n"; }
void func3() { cout << "调用了func3()函数:m_a=" << m_a << endl;; }
};
int main()
{
CC<int,int,string> cc(3,8, "芜湖");
cc.func3();
cc.func2();
}
模板类继承模板参数给出的基类
#include <iostream> // 包含头文件。
using namespace std; // 指定缺省的命名空间。
class AA {
public:
AA() { cout << "调用了AA的构造函数AA()。\n"; }
AA(int a) { cout << "调用了AA的构造函数AA(int a)。\n"; }
};
class BB {
public:
BB() { cout << "调用了BB的构造函数BB()。\n"; }
BB(int a) { cout << "调用了BB的构造函数BB(int a)。\n"; }
};
class CC {
public:
CC() { cout << "调用了CC的构造函数CC()。\n"; }
CC(int a) { cout << "调用了CC的构造函数CC(int a)。\n"; }
};
template<class T>
class DD {
public:
DD() { cout << "调用了DD的构造函数DD()。\n"; }
DD(int a) { cout << "调用了DD的构造函数DD(int a)。\n"; }
};
template<class T>
class EE : public T { // 模板类继承模板参数给出的基类。
public:
EE() :T() { cout << "调用了EE的构造函数EE()。\n"; }
EE(int a) :T(a) { cout << "调用了EE的构造函数EE(int a)。\n"; }
};
int main()
{
EE<AA> ea1; // AA作为基类。
EE<BB> eb1; // BB作为基类。
EE<CC> ec1; // CC作为基类。
EE<DD<int>> ed1; // DD<int>作为基类。
// EE<DD> ed1; // DD作为基类,错误。
}