题目

编写程序,手写一个完整的泛型动态栈类模板 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