情報隠蔽
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;
}
};このクラスの利用者は、温度が内部的にケルビンで保持されていることを知りません(あるいは知る必要もありません)。後で代わりに摂氏で保持することに決めたとしても、プライベートな実装を変更するだけで済み、パブリックインターフェースは変更されないままです。
インターフェースと実装をこのように分離することで、いくつかの利点が得られます。クラスの利用者にとっての複雑さを軽減し、内部データの予期せぬ誤用を防ぎ、コードのメンテナンスを容易にします。内部の詳細が隠されていれば、そのクラスに依存している既存のコードを壊すことなく、自由に最適化やリファクタリングを行うことができます。
チャレンジ
簡単距離を内部的にセンチメートルで保持しながら、異なる単位を扱うためのクリーンなインターフェースを提供する、情報隠蔽を実証する Distance クラスを作成しましょう。このクラスの利用者は、距離が内部でどのように保存されているかを知る(あるいは気にする)必要はありません。彼らにとって便利な単位で操作するだけです。
コードを整理するために、2つのファイルを作成します:
Distance.h: 内部表現を隠蔽しつつ、柔軟なパブリックインターフェースを公開するDistanceクラスを定義します。内部的には、距離を センチメートル(double型)で保存します。これが隠蔽された実装の詳細です。パブリックインターフェースでは、利用者が以下の操作を行えるようにする必要があります:setMeters(double m)、setCentimeters(double cm)、またはsetKilometers(double km)を使用して距離を設定するgetMeters()、getCentimeters()、またはgetKilometers()を使用して距離を取得する(これらはすべて const メソッドである必要があります)add(const Distance& other)を使用して2つの距離を加算し、新しいDistanceオブジェクトを返す
距離をゼロに初期化するデフォルトコンストラクタを含めてください。変換ロジックはメソッドの内部に隠蔽されるべきです。利用者は内部の保存形式を気にすることなく、単に
setKilometers(5)やgetMeters()を呼び出すだけです。main.cpp: 利用者が内部表現を知らなくてもクラスを操作できることを実証します。入力から2つの距離の値を読み取ります。1つ目はメートル単位、2つ目はキロメートル単位です。その後、以下の処理を行います:Distanceオブジェクトを作成し、メートル値を使用して設定する"In meters: <value> m"と出力する"In centimeters: <value> cm"と出力する"In kilometers: <value> km"と出力する- 2つ目の
Distanceオブジェクトを作成し、キロメートル値を使用して設定する - 2つの距離を加算し、その結果を保存する
"Combined in meters: <value> m"と出力する
情報隠蔽の素晴らしさは、後で内部の保存形式をセンチメートルからミリメートル(あるいは他のもの)に変更したとしても、利用者がクラスとやり取りする方法を変える必要がないことです。実装が変わっても、パブリックインターフェースは安定したまま保たれます。
すべての出力値は、<iomanip> の std::fixed と std::setprecision(2) を使用して、小数点以下2桁でフォーマットしてください。入力文字列は std::stod() を使用して double 型に変換してください。
変換の参考:1 メートル = 100 センチメートル、1 キロメートル = 1000 メートル。
自分で試してみよう
#include <iostream>
#include <string>
#include <iomanip>
#include "Distance.h"
using namespace std;
int main() {
// 入力値を読み込む
string metersInput, kmInput;
cin >> metersInput; // 1つ目の値(メートル)
cin >> kmInput; // 2つ目の値(キロメートル)
// std::stod() を使用して文字列を double に変換する
double metersValue = stod(metersInput);
double kmValue = stod(kmInput);
// 出力フォーマットを設定する
cout << fixed << setprecision(2);
// TODO: 1つ目の Distance オブジェクトを作成し、メートル値を使用して設定する
// TODO: "In meters: <value> m" と出力する
// TODO: "In centimeters: <value> cm" と出力する
// TODO: "In kilometers: <value> km" と出力する
// TODO: 2つ目の Distance オブジェクトを作成し、キロメートル値を使用して設定する
// TODO: add() メソッドを使用して2つの距離を加算する
// TODO: "Combined in meters: <value> m" と出力する
return 0;
}このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
3コンストラクタとデストラクタ
デフォルトコンストラクタ引数付きコンストラクタコピーコンストラクタムーブコンストラクタコンストラクタ初期化リスト委譲コンストラクタデストラクタ詳解Rule of Three / Five / Zeroまとめ - Stringクラス6演算子オーバーロード
演算子オーバーロード入門算術演算子のオーバーロード比較演算子のオーバーロードストリーム演算子代入演算子のオーバーロード[] と () 演算子のオーバーロード型変換演算子まとめ:Matrix クラス