C++的模板机制允许我们编写与数据类型无关的代码,使用模板实现容器类可以让同一个容器适配int、double、自定义结构体等多种数据类型,大幅减少重复代码。下面我们通过实现一个简单的动态数组容器类,来演示模板容器类的完整实现过程。

模板容器类的基础结构
首先我们需要定义模板容器类的整体框架,模板参数用于指定容器存储的元素类型,同时需要声明容器的基本成员变量,包括存储元素的指针、当前元素数量和容器容量。
#include <iostream>
#include <cstring>
// 定义模板类,T为元素类型参数
template <typename T>
class MyVector {
private:
T* data; // 存储元素的指针
int size; // 当前元素数量
int capacity; // 容器容量
public:
// 构造函数,默认容量为10
MyVector(int initCapacity = 10) : size(0), capacity(initCapacity) {
data = new T[capacity];
}
// 析构函数,释放动态分配的内存
~MyVector() {
delete[] data;
}
};
核心功能实现
添加元素功能
添加元素时需要先判断容器是否已满,如果已满则需要扩容,扩容通常是将原容量翻倍,然后拷贝原有元素到新的内存空间,再释放旧内存。
template <typename T>
void MyVector<T>::push_back(const T& element) {
// 判断是否需要扩容
if (size >= capacity) {
capacity *= 2;
T* newData = new T[capacity];
// 拷贝原有元素
for (int i = 0; i < size; i++) {
newData[i] = data[i];
}
// 释放旧内存
delete[] data;
data = newData;
}
// 添加新元素
data[size] = element;
size++;
}
获取元素与容量相关接口
我们需要提供获取元素、容器大小和容量的接口,同时重载下标运算符方便通过索引访问元素。
template <typename T>
T& MyVector<T>::operator[](int index) {
// 简单越界检查
if (index < 0 || index >= size) {
throw std::out_of_range("Index out of range");
}
return data[index];
}
template <typename T>
int MyVector<T>::getSize() const {
return size;
}
template <typename T>
int MyVector<T>::getCapacity() const {
return capacity;
}
完整代码与使用示例
将上面的功能整合后,完整的模板容器类代码如下,同时给出使用示例展示其适配不同数据类型的能力。
#include <iostream>
#include <stdexcept>
template <typename T>
class MyVector {
private:
T* data;
int size;
int capacity;
public:
MyVector(int initCapacity = 10) : size(0), capacity(initCapacity) {
data = new T[capacity];
}
~MyVector() {
delete[] data;
}
void push_back(const T& element) {
if (size >= capacity) {
capacity *= 2;
T* newData = new T[capacity];
for (int i = 0; i < size; i++) {
newData[i] = data[i];
}
delete[] data;
data = newData;
}
data[size] = element;
size++;
}
T& operator[](int index) {
if (index < 0 || index >= size) {
throw std::out_of_range("Index out of range");
}
return data[index];
}
int getSize() const {
return size;
}
int getCapacity() const {
return capacity;
}
};
// 测试代码
int main() {
// 存储int类型
MyVector<int> intVec;
intVec.push_back(1);
intVec.push_back(2);
std::cout << "intVec size: " << intVec.getSize() << std::endl;
std::cout << "intVec[0]: " << intVec[0] << std::endl;
// 存储double类型
MyVector<double> doubleVec;
doubleVec.push_back(3.14);
doubleVec.push_back(2.71);
std::cout << "doubleVec size: " << doubleVec.getSize() << std::endl;
std::cout << "doubleVec[1]: " << doubleVec[1] << std::endl;
return 0;
}
实现注意事项
- 模板类的成员函数实现通常需要和类定义放在同一个头文件中,因为模板代码需要在编译时实例化,分离编译可能导致链接错误。
- 如果容器存储的是自定义类型,需要确保该类型支持赋值操作,否则拷贝元素时会出错。
- 实际生产环境的容器类还需要实现拷贝构造函数、赋值运算符重载,避免浅拷贝导致的内存问题。
- 扩容策略可以根据实际需求调整,不一定非要翻倍,也可以采用其他扩容系数。