当前位置: 首页 > news >正文

【c++】面 向 对 象 与 抽 象 数 据 类 型

在这里插入图片描述

💻作 者 简 介:曾 与 你 一 样 迷 茫,现 以 经 验 助 你 入 门 C++。
💡个 人 主 页:@笑口常开xpr 的 个 人 主 页
📚系 列 专 栏:C++ 炼 魂 场:从 青 铜 到 王 者 的 进 阶 之 路
✨代 码 趣 语:ADT 是 “装 修 效 果 图” - - - 先 画 好 图(逻 辑 定 义),施 工 队(数 据 结 构)怎 么 砌 墙(数 组 / 链 表)我 不 管,结 果 对 就 行。
💪代 码 千 行,始 于 坚 持,每 日 敲 码,进 阶 编 程 之 路。
📦gitee 链 接:gitee

在这里插入图片描述
         写 C/C++ 时,想 实 现 “栈” 却 先 纠 结 用 数 组 还 是 链 表?其 实 不 用!抽 象 数 据 类 型(ADT)就 是 解 决 这 一 问 题 的 关 键。本 文 拆 解 ADT 的 “抽 象 + 封 装” 核 心,结 合 栈 的 案 例 对 比 C/C++ 实 现,帮 你 搞 懂 ADT 为 何 是 数 据 结 构 与 面 向 对 象 编 程 的 “桥 梁”,摆 脱 “先 纠 结 实 现、再 迷 失 逻 辑” 的 困 境。


一、抽 象 数 据 类 型 的 定 义

         抽 象 数 据 类 型(ADT)是 计 算 机 科 学 中 描 述 数 据 结 构 的 逻 辑 层 面 概 念,它 聚 焦 于 “数 据 是 什 么” 和 “数 据 能 做 什 么”,而 刻 意 隐 藏 “数 据 如 何 实 现” 的 细 节,比 如 C/C++ 中 头 文 件 提 供 的 函 数,即 隐 藏 内 部 实 现 细 节,只 提 供 相 关 的 函 数 供 用 户 使 用。其 核 心 思 想 是 封 装 与 抽 象,将 数 据 的 “逻 辑 特 性” 与 “物 理 实 现” 分 离,从 而 降 低 程 序 复 杂 度、提 高 代 码 复 用 性 和 可 维 护 性。
在这里插入图片描述
在这里插入图片描述


二、ADT 的 核 心 定 义

         ADT 本 质 上 是 一 个 “数 据 模 型”,使 用 3 个 部 分 构 成,即 数 据 对 象(D),数 据 关 系(R)和 基 本 操 作(P)。通 常 使 用 “三 元 组” 表 示:ADT = (D, R, P)。

组成部分核心含义举例说明
数据对象(D)具有相同性质的数据元素的集合“栈”的数据对象是 “所有整数的集合”
数据关系(R)数据对象中元素之间的逻辑关系集合“栈”的数据关系是元素按‘后进先出’的顺序排列
基本操作(P)数据对象的合法操作“栈”的基本操作包括:Push(入栈)、Pop(出栈)、GetTop(取栈顶)、IsEmpty(判断空)等

三、ADT 的 核 心 思 想

         ADT 的 核 心 价 值 在 于 解 决 “用 户 无 需 关 心 内 部 实 现,只 需 关 注 如 何 使 用” 的 问 题,这 依 赖 于 两 个 关 键 思 想:

(1)抽 象

  1. 抽 象 是 只 暴 露 “关 键 信 息”。对 使 用 者 而 言,只 需 知 道 ADT 的 函 数(用 来 做 什 么,如 何 使 用),无 需 知 道 内 部 如 何 存 储 数 据(如 栈 是 用 数 组 还 是 链 表 实 现)、如 何 执 行 操 作(如 Pop 时 如 何 移 动 指 针)。
  2. 例 如:C++ 使 用 “栈” 时,你 只 需 先 引 用 头 文 件#include<stack>,然 后 调 用 push(x) 就 能 让 x 入 栈,不 需 要 关 心 栈 是 用 数 组 的 “下 标 + 1” 实 现,还 是 使 用 链 表 的 “头 插 法” 实 现。
#include<iostream>
#include<stack>
using namespace std;
int main()
{stack<int> mystack;int i = 0;for (i = 0; i < 5; i++){mystack.push(i);}while (!mystack.empty()){cout << mystack.top() << " ";mystack.pop();}cout << endl;return 0;
}

在这里插入图片描述


(2)封 装

  1. 封 装 是 隐 藏 内 部 的 “实 现 细 节” 将 ADT 的 “数 据 存 储(如 数 组、链 表)” 和 “操 作 实 现(如 push 的 代 码)” 封 装 成 一 个 独 立 的 模 块 即 头 文 件 stack,不 允 许 用 户 直 接 修 改 内 部 数 据,只 能 通 过 定 义 好 的 “基 本 操 作”(函 数) 访 问。
  2. 好 处:若 后 续 需 要 修 改 实 现(如 把 “数 组 栈” 改 成 “链 表 栈”),只 要 保 持 操 作 接 口 不 变,所 有 使 用 该 ADT 的 代 码 都 无 需 修 改,极 大 降 低 维 护 成 本。

四、经 典 ADT 示 例 - - - 栈

         为 了 更 直 观 理 解 ADT,这 里 采 用 自 然 语 言 完 整 描 述 “栈” 的 ADT 定 义。

(1)数 据 对 象(D)

         D = {a₀, a₁, …, aₙ₋₁ | aᵢ ∈ 整 数 集 合,i = 0, 1, …, n-1, n ≥ 0}

(2)数 据 关 系(R)

         R = {<aᵢ₋₁, aᵢ> | aᵢ₋₁ 是 aᵢ 的 前 一 个 元 素,且 aₙ₋₁ 是 栈 顶 元 素,元 素 只 能 从 栈 顶 插 入 / 删 除 }(即 “后 进 先 出” 关 系)

(3)基 本 操 作(P)

         这 里 需 要 注 意 的 是 如 果 C++ 中 引 入 了 头 文 件 stack,则 无 需 写 栈 的 初 始 化 函 数,因 为 栈 属 于 内 置 类 型,编 译 器 会 自 动 生 成 栈 的 构 造 函 数。

操作名称前置条件功能后置条件
构造函数初始化一个空栈SS为空栈
push栈未满将元素x插入栈顶栈顶元素变为x,栈长度+1
popS 非空删除栈顶元素栈顶元素变为原栈顶的下一个元素,栈长度-1
topS 非空得到栈顶元素栈的结构不发生改变

在这里插入图片描述


五、ADT 与 “数 据 结 构” 的 区 别

         很 多 人 会 混 淆 ADT 和 数 据 结 构,核 心 区 别 在 于 逻 辑 层 面物 理 层 面 的 区 别。

对比维度抽象数据类型(ADT)数据结构
关注层面逻辑层面(“做什么”)物理层面(“怎么做”)
核心内容定义数据的逻辑关系和操作接口实现ADT的具体方式(如用数组 / 链表存储数据)
示例“栈”的ADT(定义后进先出关系和具体操作关系)“数组实现的栈”、“链表实现的栈”
关系ADT是“需求”,数据结构是“实现方案”一个ADT可以对应多种数据结构(如栈可由数组或链表实现)

六、ADT 的 核 心 优 势

  1. 降 低 耦 合 度:修 改 内 部 实 现 不 会 影 响 用 户 代 码。
  2. 提 高 复 用 性:ADT 的 接 口 是 标 准 化 的(如 栈 的 push/pop),可 在 不 同 程 序 中 直 接 复 用。
  3. 增 强 安 全 性:禁 止 用 户 直 接 操 作 内 部 数 据,避 免 因 非 法 修 改 导 致 的 逻 辑 错 误(如 直 接 修 改 栈 的 数 组 下 标 导 致 越 界 访 问)。
  4. 简 化 程 序 逻 辑:用 户 无 需 关 注 底 层 细 节,只 需 聚 焦 实 现 逻 辑(如 用 栈 解 决 “括 号 匹 配” 问 题 时,只 需 调 用 push/pop,无 需 关 心 栈 的 存 储)。

七、ADT 的 应 用:面 向 对 象 编 程 的 基 础

(1)类

         ADT 的 思 想 直 接 催 生 了 面 向 对 象 编 程 的 核 心 概 念 - - - 类(Class)

  1. 类 的 成 员 变 量 对 应 ADT 的 “数 据 对 象(D)” 和 “数 据 关 系(R)”;
  2. 类 的 成 员 方 法 对 应 ADT 的 “基 本 操 作(P)”;
  3. 类 的 “访 问 控 制(public/private)” 实 现 了 ADT 的 “封 装”(private 隐 藏 实 现,public 暴 露 接 口)。

(2)C 语 言 实 现 栈

#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
typedef int DataType;
typedef struct Stack
{DataType* array;int capacity;int size;
}Stack;
void StackInit(Stack* ps)
{assert(ps);ps->array = (DataType*)malloc(sizeof(DataType) * 3);if (NULL == ps->array){assert(0);return;}ps->capacity = 3;ps->size = 0;
}
void StackDestroy(Stack* ps)
{assert(ps);if (ps->array){free(ps->array);ps->array = NULL;ps->capacity = 0;ps->size = 0;}
}
void CheckCapacity(Stack* ps)
{if (ps->size == ps->capacity){int newcapacity = ps->capacity * 2;DataType* temp = (DataType*)realloc(ps->array,newcapacity * sizeof(DataType));if (temp == NULL){perror("realloc申请空间失败!!!");return;}ps->array = temp;ps->capacity = newcapacity;}
}
void StackPush(Stack* ps, DataType data)
{assert(ps);CheckCapacity(ps);ps->array[ps->size] = data;ps->size++;
}
int StackEmpty(Stack* ps)
{assert(ps);return 0 == ps->size;
}
void StackPop(Stack* ps)
{if (StackEmpty(ps))return;ps->size--;
}
DataType StackTop(Stack* ps)
{assert(!StackEmpty(ps));return ps->array[ps->size - 1];
}
int StackSize(Stack* ps)
{assert(ps);return ps->size;
}
int main()
{Stack s;StackInit(&s);StackPush(&s, 1);StackPush(&s, 2);StackPush(&s, 3);StackPush(&s, 4);printf("%d\n", StackTop(&s));printf("%d\n", StackSize(&s));StackPop(&s);StackPop(&s);printf("%d\n", StackTop(&s));printf("%d\n", StackSize(&s));StackDestroy(&s);return 0;
}

         C 语 言 是 面 向 过 程 的 编 程 语 言,面 向 过 程 围 绕 的 是 步 骤函 数 展 开,强 调 的 是 怎 么 做。通 过 结 构 体 和 函 数 实 现 栈,在使用时Stack 相 关 操 作 函 数 有 以 下 共 性:

  1. 每 个 函 数 的 第 一 个 参 数 都 是 Stack*
  2. 函 数 中 必 须 要 对 第 一 个 参 数 检 测,因 为 该 参 数 可 能 会 为 NULL
  3. 函 数 中 都 是 通 过 Stack* 参 数 操 作 栈 的
  4. 调 用 时 必 须 传 递 Stack 结 构 体 变 量 的 地 址

         C 语 言 中 结 构 体 中 只 能 定 义 存 放 数 据 的 结 构,操 作 数 据 的 方 法 不 能 放 在 结 构 体 中,即 数 据 和 操 作 数 据 的 方 式 是 分 离 开 的,而 且 实 现 上 相 当 复 杂 一 点,涉 及 到 大 量 指 针 操 作,稍 不 注 意 可 能 就 会 出 错。


(3)C++ 实 现 栈

在 C++ 中,用 类 实 现 “栈” 的 ADT:

#include<iostream>
using namespace std;
typedef int DataType;
class Stack
{
public:void Init(){_array = (DataType*)malloc(sizeof(DataType) * 3);if (NULL == _array){perror("malloc申请空间失败!!!");return;}_capacity = 3;_size = 0;}void Push(DataType data){CheckCapacity();_array[_size] = data;_size++;}void Pop(){if (Empty())return;_size--;}DataType Top(){ return _array[_size - 1]; }int Empty(){ return 0 == _size; }int Size() {return _size; }void Destroy(){if (_array){free(_array);_array = NULL;_capacity = 0;_size = 0;}}
private:void CheckCapacity(){if (_size == _capacity){int newcapacity = _capacity * 2;DataType* temp = (DataType*)realloc(_array, newcapacity * sizeof(DataType));if (temp == NULL){perror("realloc申请空间失败!!!");return;}_array = temp;_capacity = newcapacity;}}
private:DataType* _array;int _capacity;int _size;
};
int main()
{Stack s;s.Init();s.Push(1);s.Push(2);s.Push(3);s.Push(4);printf("%d\n", s.Top());printf("%d\n", s.Size());s.Pop();s.Pop();printf("%d\n", s.Top());printf("%d\n", s.Size());s.Destroy();return 0;
}

         C++ 是 面 向 对 象 的 编 程 语 言,面 向 对 象 围 绕 的 是 对 象对 象 之 间 的 交 互,强 调 的 是 做 什 么。C++ 中 通 过 类 可 以 将 数 据 以 及 操 作 数 据 的 方 法 进 行 完 美 结 合,通 过 访 问 权 限 可 以 控 制 那 些 方 法 在 类 外 可 以 被 调 用,即 封 装,在 使 用 时 就 像 使 用 自 己 的 成 员 一 样,更 符 合 人 类 对 一 件 事 物 的 认 知。而 且 每 个 方 法 不 需 要 传 递 Stack* 的 参 数 了,编 译 器 编 译 之 后 该 参 数 会 自 动 还 原,即 C++ 中 Stack* 参 数 是 this 指 针,它 是 由 编 译 器 维 护 的,C 语 言 中 需 要 用 户 自 己 维 护。
在这里插入图片描述


八、总 结

         抽 象 数 据 类 型(ADT)是 一 种 “从 问 题 出 发” 的 思 维 方 式:它 先 定 义 数 据 的 逻 辑 特 性 和 操 作 能 力,再 通 过 具 体 的 数 据 结 构 (数 组、链 表 等)实 现。其 核 心 价 值 在 于 “分 离 逻 辑 与 实 现”,是 降 低 程 序 复 杂 度、提 高 代 码 质 量 的 关 键 工 具,也 是 面 向 对 象 编 程 的 理 论 基 础。掌 握 ADT,能 帮 助 开 发 者 从 “关 注 代 码 细 节” 提 升 到 “设 计 数 据 模 型” 的 更 高 层 次。

http://www.dtcms.com/a/445982.html

相关文章:

  • 国内网站设计制作泰安招聘信息最新招聘2022
  • 第十二章:代理模式 - 访问控制的守护大师
  • 用wordpress建立学校网站网络营销软文案例
  • C++11线程相关
  • 住房和城乡建设统计网站网站开发公司需要招聘哪些人
  • 小土堆pytorch
  • 环保网站 中企动力建设专业的网站建设网络
  • 触摸未来2025.10.05:悟神经网络符号之伤,拥抱声音的宇宙
  • 大连鼎信网站建设wordpress简历模板
  • 关于运放的自激振荡和相位裕度
  • Edu164
  • 高端网站建设的网站四川城乡建设网站
  • 滑块(Slider)的原理与应用
  • 网站条形码如何做phpmysql网站开发技术项目式教程
  • 【LeetCode热题100】No.128——最长连续序列
  • 2025-10-04 HETAO CSP-S复赛集训营模拟赛-003 Ⅰ
  • 上海知名的网站建设公司网络优化是做啥的
  • 解码排序算法
  • 站长平台百度百度百科优化
  • 归一化分析3
  • Vue中的data为什么是函数?
  • Odoo 19 Studio 新功能实战培训
  • 手机网站qq代码市场营销的十大理论
  • 能源经济大赛选题推荐:新能源汽车试点城市政策对能源消耗的负面影响——基于技术替代效应的视角
  • 做付费软件网站怎么做广州有什么好玩的地方景点推荐
  • 【数据结构】考研算法精讲:分块查找的深度剖析 | 从“块内无序、块间有序”思想到ASL性能最优解
  • Go语言:用Go操作SQLite详解
  • arp static 概念及题目
  • 十大高端网站定制设计wordpress千万数据优化
  • 【学习笔记】kafka权威指南——第1章 初识kafka