类模板
本课属于 Coddy C++ 学习旅程的“面向对象编程”单元。第 65 课,共 104 课。
正如函数模板可以让你编写与类型无关的函数,类模板可以让你创建与类型无关的类。std::vector 这样的容器就是这样工作的:你只需定义一次结构,编译器就会为你使用的每种类型生成对应的版本。
template <typename T>
class Box {
T value;
public:
Box(T v) : value(v) {}
T getValue() const { return value; }
void setValue(T v) { value = v; }
};
int main() {
Box<int> intBox(42);
Box<std::string> strBox("Hello");
std::cout << intBox.getValue() << std::endl; // 42
std::cout << strBox.getValue() << std::endl; // Hello
}与函数模板不同,使用尖括号从类模板创建对象时,你必须明确指定类型。然后,编译器会为该类型生成完整的类定义。
类模板可以有多个类型参数,甚至还可以有整数这样的非类型参数:
template <typename T, int Size>
class FixedArray {
T data[Size];
public:
T& operator[](int index) { return data[index]; }
int size() const { return Size; }
};
FixedArray<double, 5> arr; // 包含 5 个 double 值的数组
arr[0] = 3.14;在类外定义成员函数时,你必须重复模板声明:
template <typename T>
class Container {
T* data;
public:
Container();
~Container();
};
template <typename T>
Container<T>::Container() : data(nullptr) {}
template <typename T>
Container<T>::~Container() { delete data; }类模板是 C++ 泛型编程的基础,让你能够编写可用于任意类型的可复用数据结构。
挑战
简单让我们使用类模板构建一个通用存储系统,创建一个可以存放任意数据类型的灵活容器。你会把模板类放在头文件中,并在主程序中使用不同类型来展示它的灵活性。
你需要创建两个文件:
Storage.h:定义一个名为Storage的类模板,作为一个简单容器来存放单个值,并提供一些实用操作:你的
Storage模板应包含:- 一个用于存放值的私有成员
- 一个接收初始值的构造函数
- 一个返回所存放值的
getValue()方法 - 一个用于更新所存放值的
setValue()方法 - 一个
isEmpty()方法:如果该值等于类型 T 的默认构造值,则返回true;否则返回false
另外,创建一个名为
Pair的类模板,它有两个类型参数,用于存放两个相关的值:- 用于存放第一个值和第二个值的私有成员,这两个值的类型可以不同
- 一个用于初始化两个值的构造函数
- 用于获取每个值的
getFirst()和getSecond()方法 - 一个用于打印
(<first>, <second>)的display()方法
main.cpp:读取 4 个输入,每个输入占一行:- 一个整数值
- 一个新的整数值
- 一个字符串值
- 一个 double 值
通过以下操作展示你的模板:
- 使用第一个整数创建一个
Storage<int>,并打印:Int storage: <value> - 使用
setValue()将其更新为第二个整数,然后打印:Updated: <value> - 使用输入的字符串创建一个
Storage<std::string>,并打印:String storage: <value> - 检查字符串存储是否为空,并打印:
Is empty: <true/false>(打印true或false) - 使用字符串值和 double 值创建一个
Pair<std::string, double>,然后调用display() - 使用两个整数输入创建一个
Pair<int, int>,然后调用display()
例如,输入 42、100、Hello 和 3.14 时:
Int storage: 42
Updated: 100
String storage: Hello
Is empty: false
(Hello, 3.14)
(42, 100)注意,同一个 Storage 模板可以轻松用于整数和字符串,而 Pair 可以组合不同类型的值。编译器会为你使用的每种类型组合生成单独的类定义。记得,单类型模板使用 template <typename T> 语法,包含多个类型参数的模板使用 template <typename T, typename U> 语法。
亲手试试
#include <iostream>
#include <string>
#include "Storage.h"
using namespace std;
int main() {
// 读取输入
int intValue1;
int intValue2;
string strValue;
double doubleValue;
cin >> intValue1;
cin >> intValue2;
cin >> strValue;
cin >> doubleValue;
// TODO: 用第一个整数创建 Storage<int>,输出:Int storage: <value>
// TODO: 用 setValue() 将值更新为第二个整数,输出:Updated: <value>
// TODO: 用输入的字符串创建 Storage<std::string>,输出:String storage: <value>
// TODO: 检查字符串存储是否为空,输出:Is empty: true/false
// TODO: 用字符串和 double 值创建 Pair<std::string, double>,调用 display()
// TODO: 用两个整数创建 Pair<int, int>,调用 display()
return 0;
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: C++ 在线编译器