Menu
Coddy logo textTech

継承のアクセスレベル

CoddyのC++ジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 49/104。

選択する継承の種類は、派生クラス内で基底クラスのメンバーがどのようにアクセスされるかに影響します。C++には publicprotected、および 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」関係をモデル化するものであり、圧倒的に最も一般的です。DogAnimalであるため、外部のコードはそれをAnimalとして扱うことができます。

Protected および privateinheritance は、「〜によって実装されている(implemented-in-terms-of)」という関係をモデル化します。これらは基底クラスのインターフェースを外部のコードから隠蔽するため、継承関係を公開することなく実装を再利用したい場合に便利です。private inheritance を使用すると、さらに派生した derived クラスであっても、元の Base メンバーへの access を失います。

challenge icon

チャレンジ

簡単

シンプルなデバイス階層を構築して、異なる継承の種類がメンバーのアクセス可能性にどのように影響を与えるかを探ってみましょう。基本クラス 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 継承を使用する PublicDeviceSerial: <serialNumber> と出力するメソッド displaySerial() を追加
    • protected 継承を使用する ProtectedDeviceSerial: <serialNumber> と出力するメソッド displaySerial() を追加
    • private 継承を使用する PrivateDeviceSerial: <serialNumber> と出力するメソッド displaySerial() を追加

    各派生クラスには、モデル名とシリアル番号を受け取り、モデルを基本クラスに渡してシリアル番号を設定するコンストラクタを持たせる必要があります。

  • main.cpp: 2つの入力(それぞれ別々の行)を読み込みます:
    1. モデル名 (string)
    2. シリアル番号 (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>

例えば、入力が Laptop12345 の場合:

--- 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;
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン