C++中的类模板
类模板
类模板在C++中是一种非常强大的工具,它允许程序员编写与数据类型无关的代码。简单来说,类模板允许你定义一个蓝图,这个蓝图可以用来生成具体类型的类。使用类模板可以提高代码的复用性,减少重复代码,使得代码更加简洁、易于理解和维护。
定义类模板
类模板的定义以关键字 template
开始,后面跟着模板参数列表。模板参数列表包含在尖括号 < >
中,里面定义了一个或多个模板参数。模板参数可以是类或者类型(比如 typename T
或者 class T
),也可以是非类型参数(比如整型常量)。
template <typename T>
class Box {
public:T contents;void set(const T& value) {contents = value;}T get() {return contents;}
};
在这个例子中,Box
是一个类模板,它有一个模板参数 T
。这意味着你可以用任意类型替换 T
,从而生成该类型的 Box
类。
实例化类模板
当你使用一个类模板时,需要指定模板参数,这个过程称为模板实例化。实例化模板类时,你需要在类名后面加上模板参数,参数放在尖括号 < >
中。
Box<int> intBox;
Box<double> doubleBox;
在这里,我们创建了两个 Box
对象:一个用于整数,另一个用于双精度浮点数。每个对象都可以存储和返回其类型的值。
类模板的成员函数
类模板的成员函数通常在类定义内部定义,但也可以在外部定义。如果在外部定义成员函数,需要在函数定义之前加上 template <typename T>
,并且在函数名前使用类模板的名称和模板参数列表。
template <typename T>
void Box<T>::set(const T& value) {contents = value;
}template <typename T>
T Box<T>::get() {return contents;
}
特化类模板
有时候,对于特定的数据类型,你可能希望类模板有不同的行为。这时候,可以使用模板特化。特化允许你为模板参数的特定类型定义一个特殊的类模板实现。
template <>
class Box<char> {
public:char contents;void set(const char& value) {contents = value + 1; // Just an example modification}char get() {return contents;}
};
这个例子展示了一个特化的 Box
类模板,它仅适用于 char
类型。对于 char
类型的 Box
,set
函数有了不同的行为。
类模板是C++模板编程的基石,它提供了一种灵活的方式来创建可以操作任意类型的类。通过学习和使用类模板,你可以编写更通用、更高效的C++代码。
代码示例
#include <iostream>
#include <string>
using namespace std;// 定义一个Student类用于存储学生信息
class Student {string name; // 学生姓名double score; // 学生分数public:// 构造函数,允许带默认值,便于创建无特定信息的学生对象Student(string n="no", double s=33.3) {name = n;score = s;}// 声明友元函数,允许非成员函数访问私有成员// 重载<<运算符以便于直接输出Student对象friend ostream& operator<<(ostream& o, Student s);
};// 实现重载的<<运算符
ostream& operator<<(ostream& o, Student s) {cout << s.name << "," << s.score << endl; // 输出学生的姓名和分数,然后换行return o; // 返回ostream对象,支持链式调用
}// 定义一个模板类Vector,可用于存储任意类型的动态数组
template<typename T>
class Vector {T* data; // 指向数组的指针int capacity; // 数组的容量int n; // 数组当前存储的元素数量public:// 构造函数,初始化数组的容量和大小Vector(int cap=3) {data = new T[cap]; // 动态分配存储空间if (data == 0) { // 如果分配失败,则设置容量和大小为0cap = 0;n = 0;return;}capacity = cap; // 设置容量n = 0; // 初始化元素数量为0}// 向数组末尾添加一个元素void push_back(T e) {if (n == capacity) { // 如果当前大小已达容量cout << "增加容量" << endl; // 输出提示信息T* p = new T[2 * capacity]; // 申请新的两倍大小的数组if (p) {for (int i = 0; i < n; i++)p[i] = data[i]; // 复制旧数据到新数组delete[]data; // 释放旧数组data = p; // 更新指针指向新数组capacity = 2 * capacity; // 更新容量}else {return; // 如果新数组分配失败,直接返回}}data[n] = e; // 将新元素添加到数组末尾n++; // 元素数量增加}// 重载[]运算符,允许通过下标访问数组元素T operator[](int i)const {if (i < 0 || i >= n)throw"下标非法"; // 如果下标越界,抛出异常return data[i]; // 返回下标对应的元素}// 返回数组当前存储的元素数量int size() {return n;}
};int main() {// 创建一个Vector对象,用于存储Student对象Vector<Student> v;// 向Vector中添加Student对象v.push_back(Student("Li",45.7));v.push_back(Student("Ai", 45.7));v.push_back(Student("Bi", 45.7));// 遍历Vector并输出每个Student对象for (int i = 0; i < v.size(); i++)cout << v[i];cout << endl;// 继续向Vector中添加Student对象v.push_back(Student("Liu", 45.7));v.push_back(Student("Lsi", 45.7));// 再次遍历Vector并输出每个Student对象for (int i = 0; i < v.size(); i++)cout << v[i];cout << endl;return 0;
}