數(shù)據(jù)抽象是指對(duì)外只提供基本信息并且隱藏他們的背景細(xì)節(jié),即只呈現(xiàn)程序中所需的信息而沒有提供細(xì)節(jié)。
數(shù)據(jù)抽象是一種編程(和設(shè)計(jì))技術(shù),依賴于接口和實(shí)現(xiàn)的分離。
讓我們舉一個(gè)現(xiàn)實(shí)生活中的例子。一個(gè)電視,你可以打開和關(guān)閉,改變頻道,調(diào)整音量,并添加外部組件,比如揚(yáng)聲器,錄像機(jī),以及 DVD 播放器。但是你不知道它的內(nèi)部細(xì)節(jié),也就是說(shuō),你不知道它如何通過(guò)無(wú)線技術(shù)或者通過(guò)電纜接收信號(hào),如何轉(zhuǎn)化信號(hào),以及最后將信號(hào)顯示在屏幕上。
因此,我們可以說(shuō)電視機(jī)實(shí)現(xiàn)了外部接口與內(nèi)部實(shí)現(xiàn)的清晰分離,你可以無(wú)需知道它的內(nèi)部具體實(shí)現(xiàn),就可以通過(guò)其外部接口比如電源按鈕,更換頻道,音量控制。
現(xiàn)在,如果我們談?wù)摰氖?C++ 編程, C++ 類提供了大量數(shù)據(jù)抽象的例子。他們提供了大量的針對(duì)外部世界的公有函數(shù)來(lái)滿足對(duì)象的功能或者操作對(duì)象數(shù)據(jù),即外部函數(shù)不知道類在內(nèi)部是如何實(shí)現(xiàn)的。
例如,你的程序可以在不知道函數(shù)實(shí)際使用什么算法來(lái)對(duì)給定的值進(jìn)行排序的情況下調(diào)用 sort()
函數(shù)。事實(shí)上,排序功能的底層實(shí)現(xiàn)可以在不同版本之間變化,只要接口保持不變,你的函數(shù)調(diào)用將仍然起作用。
在 C++ 中,我們使用類來(lái)定義自己的抽象數(shù)據(jù)類型( ADT )。您可以使用類 ostream 的 cout 對(duì)象對(duì)流數(shù)據(jù)進(jìn)行標(biāo)準(zhǔn)輸出如下:
#include <iostream>
using namespace std;
int main( )
{
cout << "Hello C++" <<endl;
return 0;
}
在這里,你不需要了解 cout 如何在用戶的屏幕上顯示文本。你只需要知道的公共接口和的 cout 底層實(shí)現(xiàn)是可以自由改變的。
在 C++ 中,我們使用訪問(wèn)標(biāo)號(hào)定義抽象接口類。一個(gè)類可以包含零個(gè)或多個(gè)訪問(wèn)標(biāo)簽:
一個(gè)訪問(wèn)標(biāo)號(hào)可以出現(xiàn)的次數(shù)通常是沒有限制的。每個(gè)訪問(wèn)標(biāo)號(hào)指定了隨后的成員定義的訪問(wèn)級(jí)別。這個(gè)指定的訪問(wèn)級(jí)別持續(xù)有效,知道遇到下一個(gè)訪問(wèn)標(biāo)號(hào)或看到類定義提的右花括號(hào)為止。
數(shù)據(jù)抽象提供了兩個(gè)重要的優(yōu)勢(shì):
通過(guò)只在類的私有部分定義數(shù)據(jù)成員,類作者可以自由的對(duì)數(shù)據(jù)進(jìn)行更改。如果實(shí)現(xiàn)更改,只需要檢查類的代碼看看這個(gè)改變可能造成什么影響。如果數(shù)據(jù)是公開的,那么任何可以直接訪問(wèn)舊的數(shù)據(jù)成員的函數(shù)都可能遭到破壞。
任何一個(gè)用公有和私有成員實(shí)現(xiàn)一個(gè)類的 C++ 程序都是數(shù)據(jù)抽象的一個(gè)例子??紤]下面的例子:
#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;
}
編譯和執(zhí)行上面的代碼時(shí),它產(chǎn)生以下結(jié)果:
Total 60
上面的類實(shí)現(xiàn)了把數(shù)字加起來(lái),并且返回總和。公有成員 addNum 和 getTotal 是對(duì)外的接口,用戶需要知道他們才能使用的類。私有成員 total 是用戶不需要知道的,但是它是為保證程序正常運(yùn)行類必要的。
抽象使代碼分離成接口和實(shí)現(xiàn)。所以在設(shè)計(jì)你的組件的時(shí)候,你必須保持接口獨(dú)立于實(shí)現(xiàn),因此,你才能做到在改變底層實(shí)現(xiàn)時(shí),界面將保持不變。
在這種情況下,無(wú)論任何程序使用這些接口,他們不會(huì)受到影響,只需要重新編譯最新的實(shí)現(xiàn)。