C++ 类模板是一种特殊类型的模板,用于定义类的行为,而不是定义特定的数据类型。通过使用类模板,你可以编写与特定数据类型无关的代码,并在后续实例化模板时指定具体的数据类型。这样,你可以创建适用于多种数据类型的类,而无需为每种数据类型都编写一个单独的类。
#include <bits/stdc++.h>
template <typename T>
class MyArray {
private:
T* arr;
int size;
public:
MyArray(int s);
~MyArray();
void set(int index, T value);
T get(int index);
};
template <typename T>
MyArray<T>::MyArray(int s) {
size = s;
arr = new T[s];
}
template <typename T>
MyArray<T>::~MyArray() {
delete[] arr;
}
template <typename T>
void MyArray<T>::set(int index, T value) {
if(index >= 0 && index < size) {
arr[index] = value;
}
}
template <typename T>
T MyArray<T>::get(int index) {
if(index >= 0 && index < size) {
return arr[index];
} else {
throw std::out_of_range("Index out of range");
}
}
//参数部分
int main() {
MyArray<int> intArray(10);
intArray.set(0, 42);
std::cout << intArray.get(0) << std::endl;
MyArray<double> doubleArray(5);
doubleArray.set(0, 3.14);
std::cout << doubleArray.get(0) << std::endl;
return 0;
}
在这个示例中,我们定义了一个名为 MyArray
的类模板,它接受一个类型参数 T
。MyArray
类用于表示一个动态数组,其中的元素类型为 T
。
MyArray
类有一个私有成员变量arr
,它是一个指向T
类型数组的指针,以及一个整数size
,表示数组的大小。- 构造函数
MyArray(int s)
接收一个整数参数s
,用于初始化数组的大小,并分配相应的内存。 - 析构函数
~MyArray()
用于释放之前分配的内存。 set
成员函数用于设置数组中指定索引位置的值。get
成员函数用于获取数组中指定索引位置的值。
注意,类模板的定义通常放在一个头文件中,这样当其他代码包含这个头文件时,编译器可以看到模板的定义,并可以实例化模板。
#include <bits/stdc++.h>
template <class numtype>
class Compare
{
public:
Compare(numtype a,numtype b)
{
x = a;
y = b;
}
numtype max()
{
return (x > y)? x : y;
}
numtype min()
{
return (x < y)? x : y;
}
private:
numtype x , y;
};
int main ()
{
Compare<int>cmp1(3,7);
std::cout<<cmp1.max()<<"is the Maxinum of two integer numbers."<<std::endl;
std::cout<<cmp1.min()<<"is the Mininum of two integer numbers."<<std::endl<<std::endl;
Compare<double>cmp2(28.2,73.2);
std::cout<<cmp2.max()<<"is the Maxinum of two integer numbers."<<std::endl;
std::cout<<cmp2.min()<<"is the Mininum of two integer numbers."<<std::endl<<std::endl;
Compare<char>cmp3('a','A');
std::cout<<cmp3.max()<<"is the Maxinum of two integer numbers."<<std::endl;
std::cout<<cmp3.min()<<"is the Mininum of two integer numbers."<<std::endl<<std::endl;
return 0;
}
函数类型暂定为numtype,在定义对象时如
Compare<int>cmp1(3,7);
进行编译时就会将类模板中的虚拟类型名numtype全部用实际的类型替代。
在使用C++类模板时,有几个关键的注意事项需要牢记:
- 类型参数(Type Parameters):
- 类模板使用类型参数来定义可以适用于多种数据类型的类。类型参数通常在模板声明中使用
typename
或class
关键字来指定。 - 模板类型参数可以是任何合法的C++类型,包括内置类型、用户定义的类型、指针类型等。
- 类模板使用类型参数来定义可以适用于多种数据类型的类。类型参数通常在模板声明中使用
- 实例化(Instantiation):
- 类模板本身并不生成类或对象代码,只有当模板被实例化时,编译器才会生成相应的类或对象代码。
- 实例化可以通过在模板名后添加尖括号中的类型参数来完成,例如
MyArray<int>
或MyArray<double>
。
- 成员函数定义的位置:
- 如果类模板的成员函数定义在类模板声明之外,那么这些成员函数的定义也需要使用
template <typename T>
来指明它们属于哪个模板。 - 如果成员函数定义在类模板声明内部,则不需要再次指定
template <typename T>
。
- 如果类模板的成员函数定义在类模板声明之外,那么这些成员函数的定义也需要使用
- 编译时生成代码:
- 对于每种不同的类型参数,编译器都会生成独立的代码。这可能导致编译时间增加,特别是当使用大量不同的类型参数实例化模板时。
- 由于生成的代码是独立的,模板实例化之间不会共享代码,这可能导致代码膨胀。
- 默认类型参数:
- 类模板可以具有默认类型参数,这使得在实例化模板时可以省略某些类型参数。
- 默认类型参数提供了一种灵活性,允许用户根据需要提供部分或全部类型参数。
- 模板特化(Template Specialization):
- 模板特化允许为特定的类型参数提供定制的模板实现。
- 这对于处理某些特殊类型或优化特定类型的性能非常有用。
- 非类型模板参数:
- 除了类型参数外,C++还支持非类型模板参数,如整数常量或指针。
- 非类型模板参数在某些情况下非常有用,但需要注意它们的限制和约束。
- 名字解析和依赖类型:
- 在模板中,特别是在涉及到嵌套模板或复杂类型时,名字解析可能会变得复杂。
- 依赖类型(即依赖于模板参数的类型)也可能导致一些不易察觉的问题,因为它们可能不在模板定义的上下文中完全可见。
- 类型推导:
- 当使用自动类型推导(如auto关键字)与模板时,需要特别注意推导出的类型是否与模板的期望类型匹配。
- 错误处理:
- 由于模板是在编译时展开的,因此任何与类型不匹配或不符合模板约束的错误都将在编译时捕获。
- 这要求开发者对类型系统和模板约束有深入的理解,以便能够正确诊断和解决编译时错误。
在使用类模板时,理解这些注意事项并遵循最佳实践可以帮助你更有效地利用模板,并避免常见的错误和问题。