2、【C++】資料抽象/資料封裝/介面(抽象類)
一、C++資料抽象
1、定義
資料抽象是指,只向外界提供關鍵資訊,並隱藏其後臺的實現細節,即只表現必要的資訊而不呈現細節。資料抽象是一種依賴於介面和實現分離的程式設計(設計)技術。
C++類為資料抽象提供了可能。它們向外界提供了大量用於操作物件資料的公共方法,也就是說,外界實際上並不清楚類的內部實現。
2、資料抽象的好處
資料抽象有兩個重要的優勢:
(1)類的內部受到保護,不會因無意的使用者級錯誤導致物件狀態受損。
(2)類實現可能隨著時間的推移而發生變化,以便應對不斷變化的需求,或者應對那些要求不改變使用者級程式碼的錯誤報告。
如果只在類的私有部分定義資料成員,編寫該類的作者就可以隨意更改資料。如果實現發生改變,則只需要檢查類的程式碼,看看這個改變會導致哪些影響。如果資料是公有的,則任何直接訪問舊錶示形式的資料成員的函式都可能受到影響。
3、資料抽象的例項
C++ 程式中,任何帶有公有和私有成員的類都可以作為資料抽象的例項。請看下面的例項:
#include <iostream>
using namespace std;
class Adder{
public:
// 建構函式
Adder(int i = 0)
{
total = i;
}
// 對外的介面
void addNum(int number)
{
total += number;
}
// 對外的介面
int getTotal()
{
return total;
};
private:
// 對外隱藏的資料
int total;
};
int main( )
{
Adder a;
a.addNum(10);
a.addNum(20);
a.addNum(30);
cout << "Total " << a.getTotal() <<endl;
return 0;
}
上面的類把數字相加,並返回總和。公有成員 addNum 和 getTotal 是對外的介面,使用者需要知道它們以便使用類。私有成員 total 是使用者不需要了解的,但又是類能正常工作所必需的。
二、C++資料封裝
所有的 C++ 程式都有以下兩個基本要素:
程式語句(程式碼):這是程式中執行動作的部分,它們被稱為函式。
程式資料:資料是程式的資訊,會受到程式函式的影響。
封裝是面向物件程式設計中的把資料和操作資料的函式繫結在一起的一個概念,這樣能避免受到外界的干擾和誤用,從而確保了安全。資料封裝引申出了另一個重要的 OOP 概念,即資料隱藏。
資料封裝和資料抽象的區別:
資料封裝是一種把資料和操作資料的函式捆綁在一起的機制,資料抽象是一種僅向用戶暴露介面而把具體的實現細節隱藏起來的機制。
C++ 通過建立類來支援資料封裝和資料隱藏(public、protected、private)。我們已經知道,類包含私有成員(private)、保護成員(protected)和公有成員(public)成員。預設情況下,在類中定義的所有專案都是私有的。例如:
class Box
{
public:
double getVolume(void)
{
return length * breadth * height;
}
private:
double length; // 長度
double breadth; // 寬度
double height; // 高度
};
變數 length、breadth 和 height 都是私有的(private)。這意味著它們只能被 Box 類中的其他成員訪問,而不能被程式中其他部分訪問。這是實現封裝的一種方式。
為了使類中的成員變成公有的(即,程式中的其他部分也能訪問),必須在這些成員前使用 public 關鍵字進行宣告。所有定義在 public 識別符號後邊的變數或函式可以被程式中所有其他的函式訪問。
把一個類定義為另一個類的友元類,會暴露實現細節,從而降低了封裝性。理想的做法是儘可能地對外隱藏每個類的實現細節。
二、C++介面(抽象類)
介面描述了類的行為和功能,而不需要完成類的特定實現。
C++ 介面是使用抽象類來實現的,抽象類與資料抽象互不混淆,資料抽象是一個把實現細節與相關的資料分離開的概念。
如果類中至少有一個函式被宣告為純虛擬函式,則這個類就是抽象類。純虛擬函式是通過在宣告中使用 “= 0” 來指定的,如下所示:
class Box
{
public:
// 純虛擬函式
virtual double getVolume() = 0;
private:
double length; // 長度
double breadth; // 寬度
double height; // 高度
};
設計抽象類(通常稱為 ABC)的目的,是為了給其他類提供一個可以繼承的適當的基類。抽象類不能被用於例項化物件,它只能作為介面使用。如果試圖例項化一個抽象類的物件,會導致編譯錯誤。
因此,如果一個 ABC 的子類需要被例項化,則必須實現每個虛擬函式,這也意味著 C++ 支援使用 ABC 宣告介面。如果沒有在派生類中過載純虛擬函式,就嘗試例項化該類的物件,會導致編譯錯誤。
可用於例項化物件的類被稱為具體類。請看下面的例項,基類 Shape 提供了一個介面 getArea(),在兩個派生類 Rectangle 和 Triangle 中分別實現了 getArea():
#include <iostream>
using namespace std;
// 基類
class Shape
{
public:
// 提供介面框架的純虛擬函式
virtual int getArea() = 0;
void setWidth(int w)
{
width = w;
}
void setHeight(int h)
{
height = h;
}
protected:
int width;
int height;
};
// 派生類
class Rectangle: public Shape
{
public:
int getArea()
{
return (width * height);
}
};
class Triangle: public Shape
{
public:
int getArea()
{
return (width * height)/2;
}
};
int main(void)
{
Rectangle Rect;
Triangle Tri;
Rect.setWidth(5);
Rect.setHeight(7);
// 輸出物件的面積
cout << "Total Rectangle area: " << Rect.getArea() << endl;
Tri.setWidth(5);
Tri.setHeight(7);
// 輸出物件的面積
cout << "Total Triangle area: " << Tri.getArea() << endl;
return 0;
}