継承のアクセスレベル
CoddyのC++ジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 49/104。
選択する継承の種類は、派生クラス内で基底クラスのメンバーがどのようにアクセスされるかに影響します。C++には public、protected、および private 継承の3つのオプションが用意されています。
各継承型がメンバーの `access` をどのように変換するかを以下に示します:
| `Base` メンバー | `public` `inheritance` | `protected` `inheritance` | `private` `inheritance` |
|---|---|---|---|
| `public` | `public` | `protected` | `private` |
| `protected` | `protected` | `protected` | `private` |
| `private` | `inaccessible` | `inaccessible` | `inaccessible` |
class Base {
public:
int pub;
protected:
int prot;
private:
int priv;
};
class PublicDerived : public Base {
// pub は public、prot は protected、priv はアクセス不可
};
class ProtectedDerived : protected Base {
// pub は protected、prot は protected、priv はアクセス不可
};
class PrivateDerived : private Base {
// pub は private、prot は private、priv はアクセス不可
};Public inheritanceは「is-a」関係をモデル化するものであり、圧倒的に最も一般的です。DogはAnimalであるため、外部のコードはそれをAnimalとして扱うことができます。
Protected および private の inheritance は、「〜によって実装されている(implemented-in-terms-of)」という関係をモデル化します。これらは基底クラスのインターフェースを外部のコードから隠蔽するため、継承関係を公開することなく実装を再利用したい場合に便利です。private inheritance を使用すると、さらに派生した derived クラスであっても、元の Base メンバーへの access を失います。
チャレンジ
簡単シンプルなデバイス階層を構築して、異なる継承の種類がメンバーのアクセス可能性にどのように影響を与えるかを探ってみましょう。基本クラス Device と、それぞれ異なる継承タイプを使用する3つの派生クラスを作成し、public、protected、private 継承がメンバーアクセスをどのように変換するかを直接確認します。
コードは2つのファイルに整理します:
Device.h: 異なるアクセスレベルに3つのメンバーを持つ基本クラスDeviceを定義します:- public な
std::string model - protected な
int serialNumber - private な
int internalCode(デフォルトで 999 に設定) Model: <model>と出力する public メソッドshowModel()
次に、異なる継承の種類を使用して、それぞれ
Deviceから継承する3つの派生クラスを作成します:- public 継承を使用する
PublicDevice—Serial: <serialNumber>と出力するメソッドdisplaySerial()を追加 - protected 継承を使用する
ProtectedDevice—Serial: <serialNumber>と出力するメソッドdisplaySerial()を追加 - private 継承を使用する
PrivateDevice—Serial: <serialNumber>と出力するメソッドdisplaySerial()を追加
各派生クラスには、モデル名とシリアル番号を受け取り、モデルを基本クラスに渡してシリアル番号を設定するコンストラクタを持たせる必要があります。
- public な
main.cpp: 2つの入力(それぞれ別々の行)を読み込みます:- モデル名 (string)
- シリアル番号 (integer)
同じ入力値を使って、各派生型のオブジェクトを1つずつ作成します。その後、アクセスの違いを実証します:
PublicDeviceの場合:- オブジェクト上で直接
showModel()を呼び出します(public 継承によって public のまま維持されるため動作します) modelに直接アクセスして印刷します:Direct model access: <model>displaySerial()を呼び出します
ProtectedDeviceおよびPrivateDeviceの場合:displaySerial()のみを呼び出します(継承されたshowModel()やmodelは外部から直接アクセスできなくなります)
出力フォーマット:
--- PublicDevice --- Model: <model> Direct model access: <model> Serial: <serial> --- ProtectedDevice --- Serial: <serial> --- PrivateDevice --- Serial: <serial>
例えば、入力が Laptop と 12345 の場合:
--- PublicDevice ---
Model: Laptop
Direct model access: Laptop
Serial: 12345
--- ProtectedDevice ---
Serial: 12345
--- PrivateDevice ---
Serial: 12345継承された public メンバーへの外部アクセスを許可するのは PublicDevice のみであることに注目してください。他の継承タイプは基本クラスのインターフェースを外部コードから隠蔽しますが、派生クラス自体は自身のメソッドを通じて内部的に protected メンバーにアクセスできます。
自分で試してみよう
#include <iostream>
#include <string>
#include "Device.h"
using namespace std;
int main() {
// 入力を読み取る
string modelName;
int serialNum;
getline(cin, modelName);
cin >> serialNum;
// TODO: 入力値を使って各派生型のオブジェクトを作成する
// PublicDevice pubDev(modelName, serialNum);
// ProtectedDevice protDev(modelName, serialNum);
// PrivateDevice privDev(modelName, serialNum);
// TODO: Demonstrate PublicDevice access
cout << "--- PublicDevice ---" << endl;
// - オブジェクトで直接 showModel() を呼び出す
// - Access model directly and print: Direct model access: <model>
// - displaySerial() を呼び出す
// TODO: Demonstrate ProtectedDevice access
cout << "--- ProtectedDevice ---" << endl;
// - displaySerial() のみを呼び出す(showModel と model は公開アクセスできない)
// TODO: Demonstrate PrivateDevice access
cout << "--- PrivateDevice ---" << endl;
// - displaySerial() のみを呼び出す(showModel と model は公開アクセスできない)
return 0;
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
3コンストラクタとデストラクタ
デフォルトコンストラクタ引数付きコンストラクタコピーコンストラクタムーブコンストラクタコンストラクタ初期化リスト委譲コンストラクタデストラクタ詳解Rule of Three / Five / Zeroまとめ - Stringクラス6演算子オーバーロード
演算子オーバーロード入門算術演算子のオーバーロード比較演算子のオーバーロードストリーム演算子代入演算子のオーバーロード[] と () 演算子のオーバーロード型変換演算子まとめ:Matrix クラス