Menu
Coddy logo textTech

継承のアクセスレベル

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

選択する継承タイプは、派生クラスで基底クラスのメンバにどのようにアクセスするかに影響します。C++には、publicprotected、およびprivate継承の3つのオプションがあります。

各継承タイプがメンバアクセスをどのように変換するかは以下の通りです:

基底メンバpublic継承protected継承private継承
publicpublicprotectedprivate
protectedprotectedprotectedprivate
privateアクセス不可アクセス不可アクセス不可
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 はアクセス不可
};

公開継承は「is-a」関係をモデル化するもので、断然、最も一般的です。DogAnimalであるため、外部コードはそれを1つのものとして扱うことができます。

プロテクト継承とプライベート継承は、「〜を使って実装されている(implemented-in-terms-of)」という関係をモデル化します。これらは基底クラスのインターフェースを外部のコードから隠すため、継承関係を公開せずに実装を再利用したい場合に便利です。プライベート継承では、さらに派生したクラスであっても、元の基底クラスのメンバへのアクセス権を失います。

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. モデル名 (文字列)
    2. シリアル番号 (整数)

    同じ入力値を使用して、各派生型のオブジェクトを1つずつ作成します。次に、アクセスの違いを示します:

    PublicDevice の場合:

    • オブジェクトに対して直接 showModel() を呼び出します(public 継承により public のまま維持されるため機能します)
    • model に直接アクセスし、Direct model access: <model> と出力します
    • displaySerial() を呼び出します

    ProtectedDevice および PrivateDevice の場合:

    • displaySerial() のみを呼び出します(継承された showModel()model は、外部から public にアクセスできなくなっています)

    出力形式:

    --- 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

PublicDevice だけが、継承された public メンバーへの外部アクセスを許可していることに注目してください。他の継承タイプは、外部コードからベースクラスのインターフェースを隠しますが、派生クラスは自身のメソッドを通じて内部的に protected メンバーにアクセスし続けることができます。

チートシート

C++には、派生クラスで基底クラスのメンバにどのようにアクセスするかを制御する3つの継承タイプがあります:

基底クラスのメンバpublic継承protected継承private継承
publicpublicprotectedprivate
protectedprotectedprotectedprivate
privateアクセス不可アクセス不可アクセス不可
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継承は「is-a」関係をモデル化し、最も一般的です。外部のコードは、派生クラスを通じて基底クラスのpublicメンバにアクセスできます。

protected継承およびprivate継承は「〜を使って実装される(implemented-in-terms-of)」関係をモデル化します。これらは外部のコードから基底クラスのインターフェースを隠します。private継承では、さらにその先の派生クラスも元の基底クラスのメンバへのアクセス権を失います。

自分で試してみよう

#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: PublicDevice のアクセスを実演する
    cout << "--- PublicDevice ---" << endl;
    // - オブジェクトに対して直接 showModel() を呼び出す
    // - model に直接アクセスして出力する: Direct model access: <model>
    // - displaySerial() を呼び出す
    
    // TODO: ProtectedDevice のアクセスを実演する
    cout << "--- ProtectedDevice ---" << endl;
    // - displaySerial() のみを呼び出す (showModel と model は公開アクセス不可)
    
    // TODO: PrivateDevice のアクセスを実演する
    cout << "--- PrivateDevice ---" << endl;
    // - displaySerial() のみを呼び出す (showModel と model は公開アクセス不可)
    
    return 0;
}
quiz icon腕試し

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

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