C++ 中的数据抽象


数据抽象是指只向外界提供必要的信息,隐藏其背景细节,即在程序中表示所需的信息,而不呈现细节。

数据抽象是一种依赖于接口和实现分离的编程(和设计)技术。

让我们以现实生活中的电视为例,您可以打开和关闭电视、更改频道、调节音量以及添加扬声器、录像机和 DVD 播放器等外部组件,但您不知道其内部细节,即也就是说,您不知道它如何通过空气或电缆接收信号,如何翻译它们,并最终将它们显示在屏幕上。

因此,我们可以说电视明确地将其内部实现与其外部接口分开,您可以使用其接口(如电源按钮、频道变换器和音量控制),而无需了解其内部结构。

在 C++ 中,类提供了高级别的数据抽象。它们向外界提供了足够的公共方法来使用对象的功能并操作对象数据,即状态,而无需实际知道类在内部是如何实现的。

例如,您的程序可以调用sort()函数,而不知道该函数实际使用什么算法对给定值进行排序。事实上,排序功能的底层实现可能会在库的版本之间发生变化,只要接口保持不变,您的函数调用仍然有效。

在 C++ 中,我们使用来定义我们自己的抽象数据类型 (ADT)。您可以使用ostream类的cout对象将数据流式传输到标准输出,如下所示 -

#include <iostream>
using namespace std;

int main() {
   cout << "Hello C++" <<endl;
   return 0;
}

在这里,您不需要了解cout如何在用户屏幕上显示文本。您只需要知道公共接口,并且“cout”的底层实现可以自由更改。

访问标签强制抽象

在 C++ 中,我们使用访问标签来定义类的抽象接口。一个类可以包含零个或多个访问标签 -

  • 使用公共标签定义的成员可供程序的所有部分访问。类型的数据抽象视图由其公共成员定义。

  • 使用私有标签定义的成员无法被使用该类的代码访问。私有部分对使用该类型的代码隐藏了实现。

访问标签出现的频率没有限制。每个访问标签指定后续成员定义的访问级别。指定的访问级别保持有效,直到遇到下一个访问标签或看到类主体的右大括号为止。

数据抽象的好处

数据抽象提供了两个重要的优点 -

  • 类内部受到保护,不会出现无意的用户级错误,这些错误可能会破坏对象的状态。

  • 类实现可以随着时间的推移而发展,以响应不断变化的需求或错误报告,而不需要更改用户级代码。

通过仅在类的私有部分中定义数据成员,类作者可以自由地对数据进行更改。如果实现发生更改,则只需检查类代码即可了解更改可能产生的影响。如果数据是公共的,则任何直接访问旧表示的数据成员的函数都可能被破坏。

数据抽象示例

任何实现具有公共和私有成员的类的 C++ 程序都是数据抽象的一个示例。考虑以下示例 -

#include <iostream>
using namespace std;

class Adder {
   public:
      // constructor
      Adder(int i = 0) {
         total = i;
      }
      
      // interface to outside world
      void addNum(int number) {
         total += number;
      }
      
      // interface to outside world
      int getTotal() {
         return total;
      };
      
   private:
      // hidden data from outside world
      int total;
};

int main() {
   Adder a;
   
   a.addNum(10);
   a.addNum(20);
   a.addNum(30);

   cout << "Total " << a.getTotal() <<endl;
   return 0;
}

当上面的代码被编译并执行时,它会产生以下结果 -

Total 60

上面的类将数字相加,并返回总和。公共成员 - addNumgetTotal是与外界的接口,用户需要知道它们才能使用该类。私有成员总数是用户不需要知道的东西,但类正常运行是必需的。

设计策略

抽象将代码分为接口和实现。因此,在设计组件时,必须保持接口独立于实现,这样,如果更改底层实现,接口将保持不变。

在这种情况下,无论程序使用这些接口,它们都不会受到影响,只需要使用最新的实现重新编译。