第10章 对象和类——对象和类(六) 抽象数据类型
本文章是作者根据史蒂芬·普拉达所著的《C++ Primer Plus》而整理出的读书笔记,如果您在浏览过程中发现了什么错误,烦请告知。另外,此书由浅入深,非常适合有C语言基础的人学习,感兴趣的朋友可以自行阅读此书籍。
数据类型
我们先了解一下什么是数据类型。数据类型,是指一组性质相同的值的集合即定义在此集合上的一些操作的总称。数据类型是按照值的不同进行划分的。在高级语言中,每个变量、常量和表达式都有各自的取值范围。类型就用来说明变量或表达式的取值范围和所能进行的操作。
C++的数据类型有以下几种:
- 基本类型:也称原子类型,该类型不可以再分解,包括整型、浮点型、字符型、布尔型。
- 复合类型:也称结构类型,是由基本类型或其他复合数据类型组成的类型,是可以再分解的,包括数组、指针、引用、结构体。
- 枚举类型:枚举类型用于定义一组具有相关性的常量,这些常量被称为枚举值。枚举值可以像整数一样使用,但其取值被限定为预先定义的枚举列表中的一个。
- 自定义数据类型:使用class和struct 关键字来创建自定义类型,这些类型可以包含自定义的数据成员和成员函数。
当我们自定义的数据类型表示的是一个抽象的而非具体的概念时,那么就是抽象数据类型。
抽象数据类型
之前文章定义的Student类很具体,它保存了学生的姓名、学号、各科成绩,也可以计算总分和平均分。但是,我们也可以通过定义类来表示更通用的概念。C++程序使用栈来管理自动变量。当新的自动变量被生成后,它们被添加到栈顶;消亡时,从栈中删除它们。接下来,我们实现一个栈。
我们要设计一个栈类,首先要抽象出它的特征,即就是数据 + 方法:
1,可以存储多个数据项。
2,可以压入数据。
3,可以弹出数据。
4,可以查看是否为空。
5,可以查看是否为满。
根据特征,我们可以写出这样的类声明:
#ifndef _MY_STACK_H_
#define _MY_STACK_H_
class Stack
{
public:
Stack();
bool push(int x);
bool pop(int x); //我们期望知道弹出的数据是什么
bool is_empty();
bool is_full();
private:
static const int MAX_SIZE = 20;
int m_items[MAX_SIZE];
int top;
};
#endif
我们使用了一个数组来充当栈,这个数组的大小被静态常量限制为20。
这个类有些问题,首先,如果后续要修改存储的元素的类型(当前是int型),那么就需要直接修改这个类中的代码,以及push和pop的参数列表。我们可以把类型提出来,使用typedef取个别名,后续如果要修改栈中存放的数据类型,可以直接修改typedef处的代码。
另外,push和pop的参数可以改为引用,可以节省创建临时变量的时间,对于push的参数我们不允许修改,因此也设置为const。
最后,判断是栈是空的还是满的,不应允许修改栈中的数据,因此需要将相关函数定义为const成员函数。
优化后的代码如下:
//stack.hpp
#ifndef _MY_STACK_H_
#define _MY_STACK_H_
typedef int Item;
class Stack
{
public:
Stack();
bool push(const Item &x);
bool pop(Item &x);
bool is_empty() const;
bool is_full() const;
private:
static const int MAX_SIZE = 20;
Item m_items[MAX_SIZE];
int top; //总是指向栈顶元素+1的位置
};
#endif
我们再实现它的类方法:
//stack.cpp
#include "stack.hpp"
Stack::Stack()
{
top = 0;
}
bool Stack::push(const Item &x)
{
if(is_full())
{
return false;
}
m_items[top++] = x;
return true;
}
bool Stack::pop(Item &x)
{
if(is_empty())
{
return false;
}
x = m_items[--top];
return true;
}
bool Stack::is_empty() const
{
return top == 0;
}
bool Stack::is_full() const
{
return top == MAX_SIZE;
}
我们再创建一个小程序使用下这个类:
#include <iostream>
#include <cctype>
#include "stack.hpp"
using namespace std;
int main()
{
Stack st;
char ch;
int po;
cout << "Please enter rA(a) to push , P(p) to pop, Q(q) to quit: " << endl;
while(cin >> ch && toupper(ch) != 'Q')
{
while(cin.get() != '\n')
continue;
if(!isalpha(ch))
{
cout << '\a';
continue;
}
switch(ch)
{
case 'A':
case 'a':
cout << "Enter a PO number to add: " ;
while(!(cin >> po))
{
cout << "Please enter a number!" ;
cout << endl;
cin.clear();
while (cin.get() != '\n')
continue;
cout << "Enter a PO number to add: " ;
}
if(st.is_full())
{
cout << "stack already full" << endl;
}
else
{
st.push(po);
}
break;
case 'P':
case 'p':
if(st.is_empty())
{
cout << "stack already empty" << endl;
}
else
{
st.pop(po);
cout << "PO #" << po << " poped" << endl;
}
break;
}
cout << "Please enter A(a) to push , P(p) to pop, Q(q) to quit: " << endl;
}
cout << "Bye~" << endl;
return 0;
}
程序运行结果如下:
Please enter rA(a) to push , P(p) to pop, Q(q) to quit:
a
Enter a PO number to add: 1
Please enter A(a) to push , P(p) to pop, Q(q) to quit:
a
Enter a PO number to add: 2
Please enter A(a) to push , P(p) to pop, Q(q) to quit:
a
Enter a PO number to add: 3
Please enter A(a) to push , P(p) to pop, Q(q) to quit:
a
Enter a PO number to add: 4
Please enter A(a) to push , P(p) to pop, Q(q) to quit:
a
Enter a PO number to add: 5
Please enter A(a) to push , P(p) to pop, Q(q) to quit:
p
PO #5 poped
Please enter A(a) to push , P(p) to pop, Q(q) to quit:
p
PO #4 poped
Please enter A(a) to push , P(p) to pop, Q(q) to quit:
p
PO #3 poped
Please enter A(a) to push , P(p) to pop, Q(q) to quit:
p
PO #2 poped
Please enter A(a) to push , P(p) to pop, Q(q) to quit:
p
PO #1 poped
Please enter A(a) to push , P(p) to pop, Q(q) to quit:
p
stack already empty
Please enter A(a) to push , P(p) to pop, Q(q) to quit:
q
Bye~
在使用类的程序中,我们包含了cctype这个头文件,它是cctype(字符处理库)中定义了有关字符判断与处理的库函数。以下是一些常用的方法:
方法 | 说明 |
---|---|
isalpha() | 判断一个字符是否是字母(a-z 或 A-Z) |
isdigit() | 判断一个字符是否是数字(0-9)。 |
isalnum() | 判断一个字符是否是字母或数字(a-z、A-Z 或 0-9)。 |
islower() | 判断一个字符是否是小写字母(a-z)。 |
isupper() | 判断一个字符是否是大写字母(A-Z)。 |
isspace() | 判断一个字符是否是空白字符(空格、制表符、换行符等)。 |
isblank() | 判断一个字符是否是空白字符(空格或制表符)。 |
ispunct() | 判断一个字符是否是标点字符。 |
isprint() | 判断一个字符是否是可打印字符(非控制字符)。 |
iscntrl() | 判断一个字符是否是控制字符(非打印字符)。 |
toupper() | 将一个字符转换为大写字母。 |
tolower() | 将一个字符转换为小写字母。 |
注意,字符处理库cctype的方法中每次只能处理一个字符。因此,我们可以通过isalpha()来判断用户选择使用哪个功能,键入输入是'A'/'a','P'/'p',还是'Q'/'q',但我们不能通过isdigit()来判断100是否是数字。
本文来自博客园,作者:superbmc,转载请注明原文链接:https://www.cnblogs.com/superbmc/p/18088617
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!