情報隠蔽
CoddyのC++ジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 36/104。
情報隠蔽は、単にアクセス指定子を使用することにとどまりません。これは、データだけでなく、クラスが内部でどのように動作するかという実装の詳細も隠す設計原則です。
目的は、クラスのユーザーが知る必要のあるものだけを公開し、それ以外をすべて隠すことです。これにより、クラスを使用するコードに影響を与えずに、内部の実装を変更できます。
class Temperature {
double kelvin; // 内部表現 - 隠された詳細
public:
void setCelsius(double c) {
kelvin = c + 273.15; // ユーザーから隠された変換
}
double getCelsius() const {
return kelvin - 273.15;
}
double getFahrenheit() const {
return (kelvin - 273.15) * 9.0/5.0 + 32;
}
};この class のユーザーは、温度が内部でケルビン単位で保存されていることを知りません(知る必要もありません)。後で温度を摂氏で保存することに決めた場合でも、private implementation だけを変更すればよく、public interface は変更されません。
インターフェースとimplementationを分離することで、いくつかの利点が得られます。classの利用者にとっての複雑さが軽減され、internalデータの意図しない誤用を防ぎ、コードの保守も容易になります。internalの詳細が隠されていれば、classに依存する既存のコードを壊すことなく、自由に最適化やリファクタリングを行えます。
チャレンジ
簡単Distance クラスを作成して、情報隠蔽を実演しましょう。このクラスでは距離を内部的に centimeters で保存しながら、異なる単位を扱うための使いやすいインターフェースを提供します。クラスの利用者は、距離が内部でどのように保存されているかを知る必要も、気にする必要もありません。利用者は、自分にとって便利な単位を使って操作するだけです。
コードを整理するために、2つのファイルを作成します。
Distance.h:内部表現を隠しながら、柔軟な public インターフェースを公開するDistanceクラスを定義します。内部では、距離を centimeters(double)として保存します。これが隠された implementation の詳細です。public インターフェースでは、次の操作を利用できるようにします。setMeters(double m)、setCentimeters(double cm)、またはsetKilometers(double km)を使って距離を設定するgetMeters()、getCentimeters()、またはgetKilometers()を使って距離を取得する:すべて const メソッドにするadd(const Distance& other)を使って2つの距離を加算し、新しいDistanceオブジェクトを返す
距離をゼロに初期化する Default constructor を含めます。単位の変換ロジックはメソッドの内部に隠します。利用者は内部の保存形式を気にせず、
setKilometers(5)やgetMeters()を呼び出すだけで済みます。main.cpp:利用者が内部表現を知らなくてもクラスを扱えることを実演します。入力から2つの距離の値を読み取ります。1つ目は meters、2つ目は kilometers です。その後、次の処理を行います。Distanceオブジェクトを作成し、meters の値を使って設定する"In meters: <value> m"を出力する"In centimeters: <value> cm"を出力する"In kilometers: <value> km"を出力する- 2つ目の
Distanceオブジェクトを作成し、kilometers の値を使って設定する - 2つの距離を加算し、結果を保存する
"Combined in meters: <value> m"を出力する
情報隠蔽の利点は、後から内部の保存単位を centimeters から millimeters(またはその他の単位)に変更しても、利用者がクラスを操作する方法を変更せずに済むことです。implementation が変わっても、public インターフェースは安定したままです。
すべての出力値を小数点以下2桁で表示するために、<iomanip> の std::fixed と std::setprecision(2) を使用します。入力文字列は std::stod() を使って doubles に変換します。
変換の基準:1 meter = 100 centimeters、1 kilometer = 1000 meters。
自分で試してみよう
#include <iostream>
#include <string>
#include <iomanip>
#include "Distance.h"
using namespace std;
int main() {
// 入力値を読み取る
string metersInput, kmInput;
cin >> metersInput; // 最初の値はメートル単位
cin >> kmInput; // Second value in kilometers
// std::stod() を使用して文字列を double に変換する
double metersValue = stod(metersInput);
double kmValue = stod(kmInput);
// 出力フォーマットを設定する
cout << fixed << setprecision(2);
// TODO: 最初の Distance オブジェクトを作成し、メートル値を使って設定する
// TODO: "In meters: <value> m" を出力する
// TODO: Print "In centimeters: <value> cm"
// TODO: Print "In kilometers: <value> km"
// TODO: 2つ目の Distance オブジェクトを作成し、キロメートル値を使って設定する
// TODO: add() メソッドを使って2つの距離を加算する
// TODO: Print "Combined in meters: <value> m"
return 0;
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
3コンストラクタとデストラクタ
デフォルトコンストラクタパラメータ付きコンストラクタコピーコンストラクタムーブコンストラクタコンストラクタ初期化リスト委譲コンストラクタデストラクタ徹底解説Rule of Three / Five / Zero復習 - Stringクラス6演算子オーバーロード
演算子オーバーロード入門算術演算子のオーバーロード比較演算子のオーバーロードストリーム演算子代入演算子のオーバーロード[] と () の演算子オーバーロード型変換演算子復習 - Matrixクラス自分で練習してみよう: C++オンラインコンパイラ