第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是否是数字。

posted @ 2024-03-25 07:57  superbmc  阅读(4)  评论(0编辑  收藏  举报