C++データ抽象化完全マスター:インターフェースと実装の分離
データ抽象化とは、外部世界に必要な情報のみを提供し、背景の詳細を隠蔽すること、つまり、詳細を提示せずにプログラムで必要な情報を表現することを指します。
データ抽象化は、インターフェースと実装の分離に依存するプログラミング(および設計)技法です。
テレビを実例として考えてみましょう。テレビの電源を入れたり切ったり、チャンネルを変えたり、音量を調整したり、スピーカー、VCR、DVDプレーヤーなどの外部コンポーネントを追加したりできます。しかし、その内部の詳細は知りません。つまり、電波やケーブルでどのように信号を受信し、どのように変換し、最終的に画面に表示するかは知りません。
したがって、テレビは内部実装と外部インターフェースを明確に分離しており、電源ボタン、チャンネル切替、音量調整などのインターフェースを、内部構造を知らなくても操作できます。
C++では、クラスが高度な データ抽象化 を提供します。クラスは、オブジェクトの機能を操作し、オブジェクトデータ(状態)を操作するための十分なパブリックメソッドを外部世界に提供しますが、クラスが内部でどのように実装されているかを知る必要はありません。
例えば、プログラムから sort() 関数を呼び出すとき、その関数が与えられた値をソートするために実際にどのアルゴリズムを使用しているかを知る必要はありません。実際、ソート機能の基盤実装はライブラリのリリース間で変更される可能性がありますが、インターフェースが同じであれば、関数呼び出しは依然として機能します。
C++では、クラス を使用して独自の抽象データ型(ADT)を定義します。ostream クラスの cout オブジェクトを使用して、標準出力にデータをストリーミングできます:
Live Demo#include <iostream>
using namespace std;
int main() {
cout << "Hello C++" << endl;
return 0;
}
ここでは、cout がどのようにテキストをユーザーの画面に表示するかを理解する必要はありません。パブリックインターフェースのみを知ればよく、『cout』の基盤実装は自由に変更できます。
アクセスラベルによる抽象化の強制
C++では、アクセスラベルを使用してクラスへの抽象インターフェースを定義します。クラスにはゼロ個以上のアクセスラベルを含めることができます:
public ラベルで定義されたメンバは、プログラムのすべての部分からアクセス可能です。型のデータ抽象化ビューは、そのパブリックメンバによって定義されます。
private ラベルで定義されたメンバは、そのクラスを使用するコードからアクセスできません。プライベートセクションは、型を使用するコードから実装を隠蔽します。
アクセスラベルの出現回数に制限はありません。各アクセスラベルは、続くメンバ定義のアクセスレベルを指定します。指定されたアクセスレベルは、次のアクセスラベルが検出されるか、クラス本体の閉じ波括弧が見つかるまで有効です。
データ抽象化の利点
データ抽象化は2つの重要な利点を提供します:
クラスの内部が、オブジェクトの状態を破損させる可能性のある不注意なユーザーレベルのエラーから保護されます。
クラス実装は、要件変更やバグ報告への対応として時間とともに進化できますが、ユーザーレベルのコード変更は不要です。
データメンバをクラスの private セクションのみに定義することで、クラス作成者はデータの変更を自由に行えます。実装が変更された場合、その変更がどのような影響を及ぼすかを確認するためにクラスコードのみを調べれば済みます。データが public の場合、古い表現のデータメンバに直接アクセスする関数が壊れる可能性があります。
データ抽象化の例
public と private メンバを持つクラスを実装するC++プログラムはすべて、データ抽象化の例です。以下の例を考えてみましょう:
Live Demo#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;
}
上記コードをコンパイルして実行すると、以下の結果が得られます:
Total 60
上記クラスは数値を加算し、合計を返します。パブリックメンバである addNum と getTotal は外部世界へのインターフェースであり、ユーザーはクラスを使用するためにこれらを知る必要があります。プライベートメンバ total はユーザーが知る必要のないものですが、クラスが正しく動作するために必要です。
設計戦略
抽象化はコードをインターフェースと実装に分離します。したがって、コンポーネントを設計する際は、インターフェースを実装から独立させておく必要があります。そうすれば、基盤実装を変更してもインターフェースはそのまま維持されます。
この場合、これらのインターフェースを使用しているプログラムは影響を受けず、最新の実装で再コンパイルするだけで済みます。
C言語
- C++データ型完全ガイド:基本型、修飾子、ベストプラクティス
- C++演算子完全ガイド:算術・代入・関係・論理・ビット演算子と実例
- C++クラスとオブジェクト完全ガイド:オブジェクト指向プログラミングの実践
- C++クラステンプレート完全ガイド:実践的なジェネリックプログラミング
- C++ char型をマスター:宣言、ASCII、変換テクニック
- C++ストレージクラス完全解説:スコープ、ライフタイム、使い方
- C++データ構造:配列、構造体、ポインタで効率的なプログラムを構築
- C++ポリモーフィズム完全理解:仮想関数と純粋仮想関数
- C++データカプセル化:コードを守る仕組みと実装例
- Java抽象化完全ガイド: 抽象クラス・抽象メソッドで実装を隠蔽し設計を簡潔に
- Javaデータ構造: 従来クラス(Vector/Stack/Hashtable等)とコレクションフレームワーク概要