一 类模板
template <class T或者typename T>
class 类名
{
..........
}
1.1 两种不同的实现
- 在以下的两种实现中,其实第一种叫做成员函数模板,并不能称为类模板
- 因为这种实现,我们在调用时,并不需要实例化为Product这个类指定指定特定类型。
// 实现1
class Product
{
public:template<typename T>void setProduct(const T& t){qDebug()<<t;}
};
- 但下面这种实现才是真正的类模板实现
- 这种的问题是每次实例化都必须指定类型T,这意味着每个
ProductA
实例都绑定到了一个特定类型上。
template<typename T>
class ProductA
{
public:void setProduct(const T& t){qDebug()<<t;}
};
ProductA<int> procduct;
procduct.setProduct(10);
1.2 优缺点
- 如果你需要一个类能够处理多种不同类型的数据,并且这些数据类型在设计时是未知的,那么 示例 1 更加合适。
- 如果你需要一个类只处理一种特定类型的数据,并且希望在类的设计时就明确这一点,那么 示例 2 更加合适。
1.3 类模板类外定义
- 声明
template<typename T>
class SumTemplate
{
public:T sum(T a, T b);T max(T a, T b);
};
- 定义:在定义时不但要加载类名的限定符,还要声明模板参数,以及传递模板参数
template<typename T>
T SumTemplate<T>::sum(T a, T b)
{return a + b;
}template<typename T>
T SumTemplate<T>::max(T a, T b)
{return a > b ? a : b;
}
1.4 模板类
- 实例化的模板也就是模板类,模板类是一个由模板生成的类
SumTemplate<int> templateA;qDebug()<<templateA.sum(1024,1024);qDebug()<<templateA.max(1024,512);SumTemplate<float> templateB;qDebug()<<templateB.sum(1024,1024);qDebug()<<templateB.max(1024,512);
二 模板类定义不能定义在cpp中
- 如果我们将模板类定义在cpp中,那么我们就会遇到未定义的错误行为
- 对于模板类的函数声明和实现必须放在同一个.h里面
2.1 原因
- 延迟实例化: 首先当编译器遇到类模板的声明时,并不会为这个类模板创建任何的代码,因为类模板的实例化是在调用它时才会产生对应的代码。
- 如果成员函数定义位于类模板定义之外,比如在另一个
.cpp
文件中,那么就需要显式地实例化这些成员函数。这是因为编译器在处理模板类实例化时,需要知道成员函数的实现细节。如果没有显式实例化,编译器可能无法找到这些成员函数的定义。(也就是在编译阶段无法知道函数的具体细节) - 当成员函数定义直接放在类模板的定义中时,编译器可以在任何实例化该模板类的地方看到这个成员函数的定义。这种方式下,不需要显式实例化成员函数,编译器会在需要的时候自动生成特定类型的版本。
2.2 解决
- 我们可以提前在.cpp里面显示指定模板类的类型,但这种方式不推荐使用
template class SumTemplate<int>;
template class SumTemplate<float>;