C++与C语言实现Stack的对比分析

面向对象编程有三大特性:封装、继承和多态。通过下面C和C++实现Stack的代码对比,我们可以初步了解封装的概念。

目录

一、主要差异对比

1、封装性体现

2、语法便利性

3、代码组织

二、C语言实现Stack分析

1、数据结构定义

2、核心函数实现

初始化函数

销毁函数

压栈操作

其他操作

3、C实现特点

三、C++实现Stack分析

1、类定义

2、核心成员函数实现

初始化函数

压栈操作

其他操作

四、主要区别分析

1、封装性

C++实现:

C语言实现:

2、语法便利性

C++优势:

3、代码组织

C++:

C:

五、实现思路详解

C语言实现思路

C++实现思路

六、两种实现的对比总结

七、深入理解封装

八、总结


一、主要差异对比

1、封装性体现

  • C++实现 :将数据和相关操作函数都封装在类内部,通过publicprivate访问限定符进行访问控制

    • 数据成员(_a, _capacity, _top)设为private,外部无法直接访问和修改

    • 操作接口(Push, Pop, Top等)设为public,作为类的外部接口

    • 封装本质是一种更严格、更规范的管理方式,避免了数据被随意修改的风险

  • C实现:数据和函数分离,结构体成员完全公开,可以直接访问和修改

2、语法便利性

  • this指针:C++成员函数隐式传递this指针,调用时不需要显式传递对象地址

  • 缺省参数 :如Init(int n = 4)可以简化初始化调用

  • 类型系统:不需要typedef,直接使用类名作为类型

  • 命名空间 :使用std命名空间避免命名冲突

3、代码组织

  • C++:相关数据和操作集中在一个类中,结构更清晰

  • C:数据和操作分离,需要通过指针显式传递结构体


二、C语言实现Stack分析

1、数据结构定义

cpp 复制代码
typedef int STDataType;
typedef struct Stack {
    STDataType* a;      // 动态数组指针
    int top;            // 栈顶指针
    int capacity;       // 栈容量
} ST;

2、核心函数实现

初始化函数

cpp 复制代码
void STInit(ST* ps) {
    assert(ps);
    ps->a = NULL;
    ps->top = 0;
    ps->capacity = 0;
}
  • 接收Stack结构体指针

  • 将数组指针初始化为NULL,top和capacity设为0

销毁函数

cpp 复制代码
void STDestroy(ST* ps) {
    assert(ps);
    free(ps->a);
    ps->a = NULL;
    ps->top = ps->capacity = 0;
}
  • 释放动态分配的内存

  • 重置所有成员变量

压栈操作

cpp 复制代码
void STPush(ST* ps, STDataType x) {
    assert(ps);
    // 检查并扩容
    if (ps->top == ps->capacity) {
        int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
        STDataType* tmp = (STDataType*)realloc(ps->a, newcapacity * sizeof(STDataType));
        if (tmp == NULL) {
            perror("realloc fail");
            return;
        }
        ps->a = tmp;
        ps->capacity = newcapacity;
    }
    ps->a[ps->top] = x;
    ps->top++;
}
  • 检查容量不足时进行扩容

  • 初始容量为0时分配4个元素空间,否则容量翻倍

  • 将元素放入栈顶并更新top指针

其他操作

cpp 复制代码
bool STEmpty(ST* ps);       // 判断栈是否为空
void STPop(ST* ps);         // 弹出栈顶元素
STDataType STTop(ST* ps);   // 获取栈顶元素
int STSize(ST* ps);         // 获取栈大小

3、C实现特点

  • 数据和操作分离

  • 每次操作都需要传递Stack指针

  • 结构体成员可以直接访问和修改

  • 需要手动管理内存


三、C++实现Stack分析

1、类定义

cpp 复制代码
class Stack {
public:
    // 成员函数
    void Init(int n = 4);   // 初始化,带默认参数
    void Push(STDataType x);
    void Pop();
    bool Empty();
    int Top();
    void Destroy();
    
private:
    // 成员变量
    STDataType* _a;
    size_t _capacity;
    size_t _top;
};

2、核心成员函数实现

初始化函数

cpp 复制代码
void Init(int n = 4) {
    _a = (STDataType*)malloc(sizeof(STDataType) * n);
    if (nullptr == _a) {
        perror("malloc申请空间失败");
        return;
    }
    _capacity = n;
    _top = 0;
}
  • 使用默认参数简化调用

  • 直接访问成员变量(不需要传递对象指针)

压栈操作

cpp 复制代码
void Push(STDataType x) {
    if (_top == _capacity) {
        int newcapacity = _capacity * 2;
        STDataType* tmp = (STDataType*)realloc(_a, newcapacity * sizeof(STDataType));
        if (tmp == NULL) {
            perror("realloc fail");
            return;
        }
        _a = tmp;
        _capacity = newcapacity;
    }
    _a[_top++] = x;
}
  • 扩容逻辑与C版本相同

  • 直接访问成员变量,代码更简洁

其他操作

cpp 复制代码
void Pop() { assert(_top > 0); --_top; }
bool Empty() { return _top == 0; }
int Top() { assert(_top > 0); return _a[_top - 1]; }
void Destroy() { free(_a); _a = nullptr; _top = _capacity = 0; }

四、主要区别分析

1、封装性

C++实现

  • 将数据和操作数据的函数都封装在类内部

  • 使用访问限定符(public/private)控制访问权限

  • 数据成员通常设为private,防止外部直接修改

  • 提供公共接口(public方法)来操作数据

C语言实现

  • 数据和函数分离

  • 结构体成员可以直接访问和修改

  • 需要通过函数参数显式传递结构体指针

2、语法便利性

C++优势

  • 缺省参数Init(int n = 4)可以省略参数调用

  • this指针:成员函数自动获取当前对象指针,无需显式传递

  • 作用域解析 :类名直接作为类型名,无需typedef

  • 命名空间 :使用namespace避免命名冲突

3、代码组织

C++

  • 相关数据和函数组织在一个类中

  • 更符合"高内聚"的设计原则

  • 代码可读性和维护性更好

C

  • 数据和函数分离

  • 需要手动管理数据和函数的关系

  • 容易产生命名冲突


五、实现思路详解

C语言实现思路

  1. 数据结构定义

    • 使用结构体ST存储栈的数组指针、栈顶位置和容量

    • typedef定义栈元素类型,便于修改

  2. 函数设计

    • 每个操作函数都需要显式接收栈结构体指针

    • 使用断言(assert)检查指针有效性

    • 动态内存管理完全手动控制

  3. 使用方式

    • 必须先声明结构体变量

    • 每个操作都需要传递结构体地址

    • 需要显式初始化和销毁

C++实现思路

  1. 类设计

    • 将数据和操作封装在Stack类中

    • 成员变量设为private保护数据

    • 成员函数提供操作接口

  2. 自动关联

    • 成员函数自动关联到对象实例

    • 通过this指针隐式访问成员数据

    • 无需显式传递对象指针

  3. 资源管理

    • 仍使用手动内存管理(后续可改进为RAII)

    • 提供完整的初始化、销毁接口

  4. 使用便利性

    • 对象创建后直接调用方法

    • 方法调用更直观简洁

    • 缺省参数简化常见用例


六、两种实现的对比总结

特性 C实现 C++实现
数据与操作 分离 绑定在类中
访问控制 无,可直接访问所有成员 通过访问限定符控制
对象传递 需要显式传递指针 隐式this指针传递
类型定义 需要typedef 类名即类型
初始化 需要单独调用初始化函数 可带默认参数
内存管理 手动 手动(后续可用构造函数/析构函数改进)
代码组织 分散 集中

七、深入理解封装

封装不仅仅是把数据和函数放在一起,更重要的是:

  1. 访问控制 :通过public/private限制对内部数据的直接访问

  2. 接口抽象:对外提供简洁的操作接口,隐藏实现细节

  3. 数据保护:防止外部代码随意修改内部状态,保证数据一致性

  4. 实现隔离:内部实现变更不影响外部代码

**在这个Stack实现中,C++版本通过类机制实现了基本的封装,但还只是封装的初级阶段。**后续可以进一步改进:

  1. 使用构造函数和析构函数自动管理资源(RAII)

  2. 添加const成员函数保证不修改对象状态

  3. 考虑异常安全

  4. 实现拷贝控制和移动语义


八、总结

通过对比可以看出:

  1. C++的类机制提供了更好的封装性,这是最核心的区别

  2. C++语法提供了许多便利特性,简化了代码编写

  3. 当前实现中,底层逻辑和算法基本相同,主要区别在组织方式

  4. 这只是C++封装的初步展示,后续还有更多强大特性

随着深入学习,特别是了解STL中的stack实现后,会更能体会C++的强大之处。STL stack采用适配器模式,基于deque/list/vector等容器实现,展现了更高层次的抽象和设计。