题目
编写程序,手写一个完整的泛型动态栈类模板 GenericStack<T>。支持动态自动扩容、push、pop、top、empty 与 size 接口。深入掌握类模板的声明与实现必须放置在头文件中的编译链接机制(模板代码不可分离编译为 .o 二进制);分别对原生基本类型 int、std::string 以及自定义结构体对象进行具现化实例化测试。
输入格式:无需外部输入。
输出格式:输出栈模板对整型、字符串与结构体对象的入栈出栈验证。
数据范围与约定:类模板具现化、模板分离编译陷阱、泛型动态容器。
思路与算法
1. 为什么类模板不能分离到 .cpp 中定义
因为 C++ 采用包含模型(Inclusion Model)。若将类模板实现写在 .cpp 中,该 .cpp 编译时编译器不知道调用方会传入什么具体类型,无法生成目标代码;而调用方的 .cpp 只有声明,最终在链接阶段会爆发大量 undefined reference 符号未定义错误。
2. 泛型内存管理与析构
动态分配 T* data_ = new T[capacity_]; 时,必须保证在容器析构时 delete[] data_; 能够安全依次调用具体类型的析构函数。
3. 移动语义适配
支持 void push(T item) 并在内部 std::move(item),无缝兼容不可拷贝类型与高性能移动转移。
完整程序
#include <iostream>
#include <string>
#include <stdexcept>
// 泛型动态栈类模板
template <typename T>
class GenericStack {
private:
T* data_;
size_t capacity_;
size_t size_;
void expandCapacity() {
size_t newCap = (capacity_ == 0) ? 2 : capacity_ * 2;
T* newData = new T[newCap];
for (size_t i = 0; i < size_; ++i) {
newData[i] = std::move(data_[i]);
}
delete[] data_;
data_ = newData;
capacity_ = newCap;
}
public:
GenericStack() : data_(nullptr), capacity_(0), size_(0) {}
~GenericStack() {
delete[] data_;
}
void push(T val) {
if (size_ >= capacity_) {
expandCapacity();
}
data_[size_++] = std::move(val);
}
void pop() {
if (empty()) throw std::underflow_error("栈已空,无法执行 pop!");
--size_;
}
const T& top() const {
if (empty()) throw std::underflow_error("栈已空,无法执行 top!");
return data_[size_ - 1];
}
bool empty() const { return size_ == 0; }
size_t size() const { return size_; }
};
int main() {
// 1. 具现化为整型栈 GenericStack<int>
std::cout << "--- 1. 测试整型栈 GenericStack<int> ---\n";
GenericStack<int> intStack;
intStack.push(10);
intStack.push(20);
intStack.push(30);
std::cout << "整型栈顶: " << intStack.top() << "\n";
intStack.pop();
std::cout << "弹栈后新栈顶: " << intStack.top() << "\n\n";
// 2. 具现化为字符串栈 GenericStack<std::string>
std::cout << "--- 2. 测试字符串栈 GenericStack<std::string> ---\n";
GenericStack<std::string> strStack;
strStack.push("Hello");
strStack.push("Modern");
strStack.push("C++ Templates");
while (!strStack.empty()) {
std::cout << "出栈: " << strStack.top() << "\n";
strStack.pop();
}
return 0;
}运行示例
输出:
--- 1. 测试整型栈 GenericStack<int> ---
整型栈顶: 30
弹栈后新栈顶: 20
--- 2. 测试字符串栈 GenericStack<std::string> ---
出栈: C++ Templates
出栈: Modern
出栈: Hello