模板
以往,我们在编写 C++ 代码的时候,都会把变量类型、函数参数类型等指定为具体某一种类型。但假设现在我们有一个函数,它支持多种类型,我们有什么方法可以实现呢?可能有人会想可以通过函数重载来实现,但这会导致许多重复代码。这里我要引出一个新概念,泛型编程 —— 把类型参数化,在实例化时让用户指定类型。在 C++ 中,我们可以通过模板来实现泛型编程。
cpp
/**
* Copyright 2023 <Hardworking Bee>
*/
#include <iostream>
using std::cout;
// 约定俗成,模板类型参数通常用单个大写字母表示。
template <typename T>
T add(T a, T b) {
return a + b;
}
int main() {
// 编译器会根据参数类型自动推导出模板参数类型。
cout << add(1, 2) << '\n';
cout << add(1.1, 2.2) << '\n';
// 也可以显式指定模板参数类型。
cout << add<int>(1, 2) << '\n';
cout << add<double>(1.1, 2.2) << '\n';
return 0;
}调用函数时,编译器会根据模板参数类型生成对应类型的函数,这个过程称作“模板实例化”。你可以在调试模式运行以上代码,然后打开反汇编视图,可以发现上述两次 add 的调用是两个不同的函数,分别对应 int 和 double 类型。
类模板
C++ 中除了函数模板外,我们还可以编写类模板。
cpp
/**
* Copyright 2023 <Hardworking Bee>
*/
#include <iostream>
using std::cout;
template <typename T>
class Array {
template <typename T>
friend std::ostream& operator<<(std::ostream&, const Array<T>&);
private:
T* data_;
// 元素个数
int size_{0};
// 容量
int capacity_;
public:
explicit Array(int capacity = 0) {
capacity_ = capacity > 0 ? capacity : 1;
data_ = new T[capacity_];
}
~Array() {
if (data_ == nullptr) return;
delete[] data_;
}
T& operator[](int index) {
if (index < 0 || index >= capacity_)
throw std::out_of_range("index out of range");
return data_[index];
}
int size() const { return size_; }
int capacity() const { return capacity_; }
T& Push(T value) {
if (size_ < capacity_) {
data_[size_++] = value;
return data_[size_ - 1];
}
int* new_data = new T[capacity_ + 1];
for (int i = 0; i < capacity_; ++i) {
new_data[i] = data_[i];
}
new_data[capacity_] = value;
delete[] data_;
data_ = new_data;
++size_;
++capacity_;
return data_[capacity_ - 1];
}
};
template <typename T>
std::ostream& operator<<(std::ostream& os, const Array<T>& arr) {
os << '[';
int last_idx = arr.size() - 1;
for (int i = 0; i < last_idx; ++i) {
os << arr.data_[i] << ", ";
}
os << arr.data_[last_idx] << ']';
return os;
}
int main() {
Array<int> arr(10);
for (int i = 0; i < 10; ++i) {
arr.Push(i);
}
for (int i = 0; i < 10; ++i) {
cout << arr[i] << '\n';
}
cout << arr << '\n';
return 0;
}