C++のprotectedの意味と使い方について

AI実装検定のご案内

C++のprotectedは、クラスのメンバーに対するアクセス範囲を制御するアクセス指定子の一つです。

protectedに指定されたメンバーは、通常のクラス外部からはアクセスできません。

一方で、そのクラス自身や、一定の条件を満たす派生クラスなどからはアクセスできます。

主に、次の場所からアクセス可能です。

  • protectedメンバーを宣言したクラスのメンバー関数
  • そのクラスのfriend関数やfriendクラス
  • そのクラスを継承した派生クラスのメンバー関数
  • 条件を満たす派生クラスのfriend

つまり、protectedは「一般の利用者には公開したくないが、継承先のクラスには利用させたい」という場合に使われます。

目次

publicprotectedprivateの違い

C++では、クラスのメンバーに対して、主にpublicprotectedprivateの3種類のアクセス指定子を使用します。

それぞれの違いは、次のとおりです。

アクセス指定子宣言元クラス派生クラス通常のクラス外部
publicアクセス可能アクセス可能アクセス可能
protectedアクセス可能条件付きでアクセス可能アクセス不可
privateアクセス可能直接アクセス不可アクセス不可

publicの意味

publicメンバーは、クラスの内部だけでなく、クラス外部からもアクセスできます。

#include <string>

class User {
public:
    std::string name;
};

int main() {
    User user;
    user.name = "Taro";
}

publicは、クラスの利用者に公開する操作や情報に使用します。

一般的には、コンストラクタ、取得用関数、設定用関数、外部から呼び出す処理などをpublicにします。

privateの意味

privateメンバーは、原則として宣言したクラスの内部からしか直接アクセスできません。

class User {
private:
    int age_ = 20;

public:
    int getAge() const {
        return age_;
    }
};

int main() {
    User user;

    // user.age_ = 30;
    // エラー:privateメンバーにはアクセスできない

    int age = user.getAge();
}

派生クラスであっても、基底クラスのprivateメンバーへ直接アクセスすることはできません。

ただし、基底クラスが用意したpublicまたはprotectedメンバー関数を通じて、間接的に利用できる場合があります。

protectedの意味

protectedメンバーは、通常のクラス外部からはアクセスできません。

しかし、派生クラスのメンバー関数などからは、一定の条件でアクセスできます。

#include <iostream>
#include <string>

class Person {
protected:
    std::string name_;
};

class Employee : public Person {
public:
    void setName(const std::string& name) {
        name_ = name;
    }

    void showName() const {
        std::cout << name_ << '\n';
    }
};

int main() {
    Employee employee;
    employee.setName("Taro");
    employee.showName();

    // employee.name_ = "Jiro";
    // エラー:クラス外部からprotectedメンバーにはアクセスできない
}

EmployeePersonを継承しているため、Personprotectedメンバーであるname_へアクセスできます。

ただし、main関数から直接操作することはできません。

protectedの基本的な書き方

protectedは、クラス定義の中でprotected:と記述します。

class Base {
protected:
    int value_;
    void helper();
};

protected:以降に宣言されたメンバーは、次のアクセス指定子が現れるまでprotectedとして扱われます。

class Example {
public:
    void publicFunction();

protected:
    int protectedValue_;
    void protectedFunction();

private:
    int privateValue_;
};

アクセス指定子は、一つのクラス内で複数回記述できます。

class Example {
protected:
    int value1_;

public:
    void show();

protected:
    int value2_;
};

この例では、value1_value2_の両方がprotectedメンバーです。

派生クラスからprotectedメンバーを使う方法

protected変数へアクセスする例

次の例では、基底クラスAnimalのデータメンバーをprotectedにしています。

#include <iostream>
#include <string>

class Animal {
protected:
    std::string name_;
    int age_;

public:
    Animal(const std::string& name, int age)
        : name_(name), age_(age) {
    }
};

class Dog : public Animal {
public:
    Dog(const std::string& name, int age)
        : Animal(name, age) {
    }

    void introduce() const {
        std::cout << "名前: " << name_ << '\n';
        std::cout << "年齢: " << age_ << '\n';
    }
};

int main() {
    Dog dog("Pochi", 3);
    dog.introduce();

    return 0;
}

DogAnimalを継承しているため、name_age_へアクセスできます。

一方で、クラス外部から次のようにアクセスすることはできません。

Dog dog("Pochi", 3);

// dog.name_ = "Taro";
// エラー:name_はprotectedメンバー

protectedメンバー関数を使う例

protectedにできるのは、データメンバーだけではありません。

メンバー関数、コンストラクタ、デストラクタ、型エイリアス、列挙型、静的メンバーなどにも指定できます。

#include <iostream>

class Machine {
protected:
    void startEngine() {
        std::cout << "エンジンを起動しました\n";
    }
};

class Car : public Machine {
public:
    void start() {
        startEngine();
    }
};

int main() {
    Car car;
    car.start();

    // car.startEngine();
    // エラー:protectedメンバー関数には外部からアクセスできない
}

この設計では、外部の利用者はCar::start()を呼び出せます。

しかし、内部処理であるstartEngine()を直接呼び出すことはできません。

派生クラスでも自由にアクセスできるわけではない

protectedは「派生クラスなら無条件にアクセスできる」という仕組みではありません。

特に、非staticprotectedメンバーをオブジェクト経由で参照する場合は、アクセス対象となるオブジェクトの型に制限があります。

基底クラス型のオブジェクト経由ではアクセスできない

次のコードはコンパイルエラーになります。

class Base {
protected:
    int value_ = 0;
};

class Derived : public Base {
public:
    void updateBase(Base& object) {
        // object.value_ = 10;
        // エラー
    }
};

Derivedのメンバー関数内であっても、単なるBase型のオブジェクトを通じてBase::value_へアクセスすることはできません。

一方、Derived型のオブジェクトを通じたアクセスは可能です。

class Derived : public Base {
public:
    void update(Derived& object) {
        object.value_ = 10;
    }
};

兄弟クラスのオブジェクトにはアクセスできない

同じ基底クラスを継承した別の派生クラスに対しても、自由にアクセスできるわけではありません。

class Base {
protected:
    int value_ = 0;
};

class DerivedA : public Base {
};

class DerivedB : public Base {
public:
    void test(DerivedA& a, DerivedB& b) {
        // a.value_ = 1;
        // エラー

        b.value_ = 2;
    }
};

DerivedADerivedBは、どちらもBaseを継承しています。

しかし、DerivedBのメンバー関数からDerivedAオブジェクトを通じてvalue_へアクセスすることはできません。

この制限は、主に非staticprotectedメンバーをオブジェクト経由で参照する場合に関係します。

protectedと継承方法の関係

C++では、メンバーに付けるアクセス指定子とは別に、継承時にもpublicprotectedprivateを指定できます。

class Derived : public Base {
};

このpublicは、基底クラスをどのようなアクセス範囲で継承するかを表しています。

メンバーに付けるprotectedとは役割が異なります。

public継承

class Derived : public Base {
};

public継承では、基底クラスのpublicメンバーは派生クラスでもpublicとして扱われます。

基底クラスのprotectedメンバーは、派生クラスでもprotectedとして扱われます。

基底クラスのメンバー派生クラスから見た扱い
publicpublic
protectedprotected
private直接アクセス不可
class Base {
public:
    int publicValue_;

protected:
    int protectedValue_;

private:
    int privateValue_;
};

class Derived : public Base {
public:
    void test() {
        publicValue_ = 1;
        protectedValue_ = 2;

        // privateValue_ = 3;
        // エラー
    }
};

protected継承

class Derived : protected Base {
};

protected継承では、基底クラスのpublicメンバーとprotectedメンバーが、派生クラスから見てprotectedとして扱われます。

基底クラスのメンバー派生クラスから見た扱い
publicprotected
protectedprotected
private直接アクセス不可
class Base {
public:
    void publicFunction() {
    }

protected:
    void protectedFunction() {
    }
};

class Derived : protected Base {
public:
    void execute() {
        publicFunction();
        protectedFunction();
    }
};

int main() {
    Derived object;
    object.execute();

    // object.publicFunction();
    // エラー:protected継承によって外部からアクセスできない
}

private継承

class Derived : private Base {
};

private継承では、基底クラスのpublicメンバーとprotectedメンバーが、派生クラスから見てprivateとして扱われます。

基底クラスのメンバー派生クラスから見た扱い
publicprivate
protectedprivate
private直接アクセス不可

継承方法による違いをまとめると、次のようになります。

継承方法基底クラスのpublic基底クラスのprotected基底クラスのprivate
public継承publicprotected直接アクセス不可
protected継承protectedprotected直接アクセス不可
private継承privateprivate直接アクセス不可

ここで注意したいのは、基底クラスのメンバー自体の宣言が変更されるわけではない点です。

継承方法によって、派生クラスやその利用者から見たアクセス可能性が変わります。

基底クラスのprivateメンバーはどうなるのか

基底クラスのprivateメンバーは、派生クラスのオブジェクト内から消えるわけではありません。

派生クラスオブジェクトに含まれる基底クラス部分の状態として存在します。

ただし、派生クラスのコードから名前を使って直接アクセスすることはできません。

#include <iostream>

class Base {
private:
    int value_ = 100;

protected:
    int getValue() const {
        return value_;
    }
};

class Derived : public Base {
public:
    void show() const {
        std::cout << getValue() << '\n';
    }
};

この例では、Derivedからvalue_へ直接アクセスすることはできません。

しかし、基底クラスが用意したprotected関数getValue()を通じて値を取得できます。

classstructのデフォルトアクセス

C++では、classstructでデフォルトのアクセス指定が異なります。

classはデフォルトでprivate

class Example {
    int value_;
};

このvalue_は、アクセス指定子を省略しているためprivateです。

次のコードと同じ意味になります。

class Example {
private:
    int value_;
};

structはデフォルトでpublic

struct Example {
    int value;
};

このvalueは、アクセス指定子を省略しているためpublicです。

structでも、明示的にprotectedを指定できます。

struct Base {
protected:
    int value_ = 10;
};

struct Derived : Base {
    int getValue() const {
        return value_;
    }
};

なお、classstructでは継承時のデフォルトも異なります。

classで継承方法を省略するとprivate継承になります。

structで継承方法を省略するとpublic継承になります。

class DerivedClass : Base {
    // private継承
};

struct DerivedStruct : Base {
    // public継承
};

protectedコンストラクタの使い方

コンストラクタをprotectedにすると、一般のクラス外部から直接オブジェクトを生成することを制限できます。

一方で、派生クラスやfriendなど、アクセスを許可された場所からは呼び出せます。

#include <iostream>

class Shape {
protected:
    Shape() {
        std::cout << "Shapeを初期化しました\n";
    }
};

class Circle : public Shape {
public:
    Circle() {
        std::cout << "Circleを初期化しました\n";
    }
};

int main() {
    Circle circle;

    // Shape shape;
    // エラー:Shapeのコンストラクタはprotected
}

この設計では、Shapeを一般の利用者が直接生成することはできません。

しかし、派生クラスCircleのコンストラクタからは呼び出せます。

引数付きコンストラクタにも指定できます。

class Entity {
private:
    int id_;

protected:
    explicit Entity(int id)
        : id_(id) {
    }
};

class Player : public Entity {
public:
    explicit Player(int id)
        : Entity(id) {
    }
};

ただし、基底クラスを直接生成させたくない場合は、純粋仮想関数を持つ抽象クラスとして設計する方法もあります。

protectedコンストラクタと抽象クラスは目的が異なるため、設計に応じて使い分けます。

protectedデストラクタの使い方

デストラクタをprotectedにすると、一般のクラス外部から直接破棄することを制限できます。

class Base {
protected:
    ~Base() = default;
};

class Derived : public Base {
public:
    ~Derived() = default;
};

Base型のオブジェクトを外部で自動変数として生成すると、スコープ終了時にBase::~Base()を呼び出す必要があります。

しかし、デストラクタがprotectedであるため、そのようなコードは成立しません。

int main() {
    // Base object;
    // エラー:スコープ終了時にデストラクタへアクセスできない
}

また、外部から基底クラスポインタに対してdeleteすることも制限されます。

ポリモーフィックな基底クラスでは仮想デストラクタを検討する

基底クラスポインタを通じて派生クラスオブジェクトを削除する設計では、通常、基底クラスのデストラクタをpublic virtualにします。

class Base {
public:
    virtual ~Base() = default;
};

一般的な設計方針としては、次の二つがあります。

  • 基底クラスポインタから削除させる場合はpublic virtual
  • 基底クラスポインタから削除させない場合はprotected non-virtual

protectedな非仮想デストラクタと、public virtualなデストラクタは、目的が異なります。

protectedな仮想関数の使い方

protectedは、派生クラスに処理の一部だけを実装させる設計でもよく使われます。

代表的なのが、テンプレートメソッドパターンです。

#include <iostream>

class Task {
public:
    void execute() {
        beforeExecute();
        doExecute();
        afterExecute();
    }

    virtual ~Task() = default;

protected:
    virtual void doExecute() = 0;

    virtual void beforeExecute() {
        std::cout << "前処理\n";
    }

    virtual void afterExecute() {
        std::cout << "後処理\n";
    }
};

class DownloadTask : public Task {
protected:
    void doExecute() override {
        std::cout << "ダウンロード処理\n";
    }
};

int main() {
    DownloadTask task;
    task.execute();

    // task.doExecute();
    // エラー:doExecute()はprotected
}

外部の利用者はexecute()だけを呼び出します。

処理全体の流れは基底クラスが管理し、具体的な処理だけを派生クラスが実装します。

この設計には、次のような利点があります。

  • 外部に公開する操作を限定できる
  • 処理全体の順序を基底クラスが管理できる
  • 派生クラスには必要な部分だけを実装させられる
  • 実装用の仮想関数を一般利用者から隠せる

オーバーライド時にアクセス指定を変えられる

C++では、基底クラスの仮想関数と、派生クラスのオーバーライド関数で、アクセス指定子を変えることができます。

#include <iostream>

class Base {
public:
    virtual void show() {
        std::cout << "Base\n";
    }

    virtual ~Base() = default;
};

class Derived : public Base {
protected:
    void show() override {
        std::cout << "Derived\n";
    }
};

次の呼び出しは可能です。

int main() {
    Derived derived;
    Base& base = derived;

    base.show();

    // derived.show();
    // エラー:Derived::show()はprotected
}

base.show()では、呼び出し式から見えるBase::show()publicであるため、アクセスが許可されます。

実行時には仮想関数の仕組みにより、Derived::show()が呼び出されます。

ただし、基底クラスと派生クラスでアクセスレベルを変える設計は、コードの利用者を混乱させる可能性があります。

明確な意図がある場合に限定した方がよいでしょう。

friendprotectedの関係

friendとして指定された関数やクラスは、対象クラスのprivateメンバーとprotectedメンバーへアクセスできます。

#include <iostream>

class Base {
protected:
    int value_ = 100;

    friend void showValue(const Base& base);
};

void showValue(const Base& base) {
    std::cout << base.value_ << '\n';
}

showValue()Baseのメンバー関数ではありません。

しかし、friendに指定されているため、protectedメンバーであるvalue_へアクセスできます。

ただし、friendには次の特徴があります。

  • friend関係は継承されない
  • friend関係は相互的ではない
  • friend関数は対象クラスのメンバー関数になるわけではない

基底クラスのfriendが、自動的に派生クラスのfriendになるわけではありません。

protectedな型や定数を定義する方法

protectedには、データメンバーや関数以外も配置できます。

class Base {
protected:
    using ValueType = int;

    enum class State {
        Stopped,
        Running
    };

    static constexpr int maxCount = 100;
};

class Derived : public Base {
public:
    void test() {
        ValueType value = 10;
        State state = State::Running;
        int count = maxCount;

        (void)value;
        (void)state;
        (void)count;
    }
};

このように、派生クラスの実装でだけ使用する型、列挙型、定数などをprotectedにできます。

protectedを使うメリット

外部からの直接操作を防げる

protectedメンバーは通常のクラス外部からアクセスできません。

そのため、一般利用者による意図しない操作を防ぎつつ、派生クラスには必要な機能を提供できます。

派生クラス向けの拡張ポイントを提供できる

基底クラスの共通処理を、派生クラスから利用できるようにできます。

#include <iostream>
#include <string>

class Logger {
protected:
    void writeLog(const std::string& message) const {
        std::cout << message << '\n';
    }
};

class FileProcessor : public Logger {
public:
    void process() {
        writeLog("処理を開始します");
        writeLog("処理が完了しました");
    }
};

共通処理を基底クラスへまとめられる

複数の派生クラスで利用する補助処理を、基底クラスのprotectedメンバー関数として共通化できます。

class Validator {
protected:
    bool isPositive(int value) const {
        return value > 0;
    }
};

class Product : public Validator {
public:
    bool isValidPrice(int price) const {
        return isPositive(price);
    }
};

class Order : public Validator {
public:
    bool isValidQuantity(int quantity) const {
        return isPositive(quantity);
    }
};

protectedを使うデメリット

基底クラスと派生クラスの結合が強くなる

派生クラスが基底クラスのprotectedデータメンバーを直接操作すると、基底クラスの内部構造へ強く依存します。

class Base {
protected:
    int count_ = 0;
};

class Derived : public Base {
public:
    void increment() {
        ++count_;
    }
};

将来、count_の型や管理方法を変更した場合、派生クラス側の修正も必要になる可能性があります。

クラスの不変条件が壊れる可能性がある

クラスが常に守るべき状態の条件を、不変条件と呼びます。

class Account {
protected:
    int balance_ = 0;
};

class SpecialAccount : public Account {
public:
    void update() {
        balance_ = -1000;
    }
};

残高を負数にしてはいけない設計であっても、派生クラスが直接値を変更できると、不正な状態を作れてしまいます。

変更の影響範囲が広がりやすい

protectedメンバーは一般利用者には非公開ですが、派生クラスの作者には公開されています。

多数の派生クラスから利用されると、事実上、派生クラス向けのAPIになります。

そのため、引数、戻り値、名前、例外仕様などを変更すると、多くの派生クラスへ影響する可能性があります。

protected変数よりprivateとメンバー関数を検討する

多くの場合、データメンバーをprotectedにするよりも、privateにして、派生クラス向けの操作をprotectedメンバー関数として提供する方が安全です。

protected変数を直接公開する設計

class Account {
protected:
    int balance_ = 0;
};

この設計では、派生クラスがbalance_へ任意の値を代入できます。

private変数とprotected関数を使う設計

class Account {
private:
    int balance_ = 0;

protected:
    int balance() const {
        return balance_;
    }

    bool deposit(int amount) {
        if (amount <= 0) {
            return false;
        }

        balance_ += amount;
        return true;
    }

    bool withdraw(int amount) {
        if (amount <= 0 || amount > balance_) {
            return false;
        }

        balance_ -= amount;
        return true;
    }
};

この設計では、派生クラスが残高に関する操作を行えます。

一方で、残高を無制限に書き換えることはできません。

基底クラスが更新条件を管理できるため、データの整合性を保ちやすくなります。

ただし、protectedデータメンバーが常に誤りというわけではありません。

派生クラスとの強い協調を前提とする小規模な設計や、内部実装が固定されたフレームワークなどでは、採用される場合もあります。

protectedを使うべき場面

派生クラス専用の補助関数を提供する場合

class Base {
protected:
    void helper() {
        // 派生クラス向けの共通処理
    }
};

一般利用者には公開したくないものの、派生クラスでは利用させたい処理に向いています。

派生クラスにオーバーライドさせる場合

class Base {
protected:
    virtual void process() = 0;
};

外部から直接呼び出させず、派生クラスに実装だけを委ねたい処理に適しています。

基底クラスの直接生成を制限する場合

class Base {
protected:
    Base() = default;
};

基底クラスを、主に継承用途で使用させたい場合に利用できます。

派生クラス向けに読み取り専用情報を提供する場合

class Base {
private:
    int value_ = 100;

protected:
    int value() const {
        return value_;
    }
};

内部データを直接公開せず、派生クラスに必要な情報だけを提供できます。

protectedを避けた方がよい場面

継承を想定していないクラス

派生クラスを作る予定がない場合は、基本的にprotectedを使用する必要はありません。

外部に公開するものはpublic、内部実装はprivateにすると役割が明確になります。

データの整合性を厳密に守りたい場合

値の変更に条件があるデータをprotectedにすると、派生クラスが条件を無視して書き換えられます。

この場合は、データをprivateにし、検証処理を持つprotected関数を提供する方が適しています。

継承よりコンポジションが適している場合

単に別のクラスの機能を再利用したいだけなら、継承ではなくコンポジションが適している場合があります。

#include <iostream>
#include <string>

class Logger {
public:
    void write(const std::string& message) const {
        std::cout << message << '\n';
    }
};

class Service {
private:
    Logger logger_;

public:
    void execute() {
        logger_.write("処理開始");
    }
};

ServiceLoggerの一種ではなく、Loggerを所有して利用しています。

「is-a」の関係なら継承を、「has-a」の関係ならコンポジションを検討するのが基本です。

protectedを使うときの設計上のポイント

データメンバーはなるべくprivateにする

派生クラスに必要な操作だけを、protectedメンバー関数として提供すると、内部状態を管理しやすくなります。

class Counter {
private:
    int count_ = 0;

protected:
    void increment() {
        ++count_;
    }

    int count() const {
        return count_;
    }
};

protectedを派生クラス向けAPIとして考える

protectedメンバーは一般利用者には見えません。

しかし、派生クラスの作者からは利用できます。

そのため、protectedメンバーも公開APIに近い慎重さで設計する必要があります。

基底クラスの不変条件を守る

派生クラスが操作しても、基底クラスが不正な状態にならない設計を目指します。

class Progress {
private:
    int percentage_ = 0;

protected:
    void setProgress(int percentage) {
        if (percentage < 0) {
            percentage_ = 0;
        } else if (percentage > 100) {
            percentage_ = 100;
        } else {
            percentage_ = percentage;
        }
    }
};

値を直接変更させるのではなく、意味のある操作を通じて更新させることが重要です。

継承用途に応じてデストラクタを設計する

基底クラスをポリモーフィックに利用する場合は、仮想デストラクタが必要になることがあります。

class Base {
public:
    virtual ~Base() = default;
};

protectedメンバーを持つこと自体が、仮想デストラクタを必要とするわけではありません。

基底クラスポインタを通じて派生オブジェクトを削除するかどうかで判断します。

protectedを使った実践的なサンプルコード

次の例では、基底クラスが処理全体の流れを管理し、派生クラスが一部の処理だけを実装します。

#include <iostream>
#include <stdexcept>
#include <string>

class DataProcessor {
public:
    void run(const std::string& data) {
        if (data.empty()) {
            throw std::invalid_argument("データが空です");
        }

        log("処理を開始します");
        process(data);
        log("処理が完了しました");
    }

    virtual ~DataProcessor() = default;

protected:
    virtual void process(const std::string& data) = 0;

    void log(const std::string& message) const {
        std::cout << "[LOG] " << message << '\n';
    }
};

class TextProcessor : public DataProcessor {
protected:
    void process(const std::string& data) override {
        log("文字列を処理しています");
        std::cout << "入力データ: " << data << '\n';
    }
};

int main() {
    TextProcessor processor;
    processor.run("Hello, C++");

    return 0;
}

このコードでは、それぞれの役割が次のように分かれています。

  • run()は外部から呼び出すためpublic
  • process()は派生クラスが実装するためprotected
  • log()は派生クラスでも使う補助関数なのでprotected
  • デストラクタはポリモーフィックな利用を考慮してpublic virtual

外部の利用者はrun()だけを呼び出します。

処理の詳細は派生クラス側に隠されているため、公開インターフェースを小さく保てます。

C++のprotectedに関するよくある間違い

protectedならクラス外部からアクセスできる

これは誤りです。

class Base {
protected:
    int value_;
};

int main() {
    Base object;

    // object.value_ = 10;
    // エラー
}

オブジェクトがBase型であっても、アクセスする場所が通常のクラス外部であればアクセスできません。

派生クラスなら任意の基底クラスオブジェクトを操作できる

これも誤りです。

class Base {
protected:
    int value_;
};

class Derived : public Base {
public:
    void set(Base& base) {
        // base.value_ = 10;
        // エラー
    }
};

派生クラスのメンバー関数内であっても、単なる基底クラス型のオブジェクトを通じたアクセスには制限があります。

protectedprotected継承は同じ意味

両者は別の機能です。

class Base {
protected:
    int value_;
};

このprotectedは、value_というメンバーのアクセス範囲を指定しています。

class Derived : protected Base {
};

こちらのprotectedは、基底クラスのメンバーを派生クラスからどのように扱うかを指定しています。

protectedなら完全にカプセル化できる

protectedは通常のクラス外部からメンバーを隠せます。

しかし、派生クラスからはアクセスできます。

そのため、privateほど強く内部状態を保護できるわけではありません。

まとめ

C++のprotectedは、クラス外部には公開せず、派生クラスには一定の条件で利用を許可するアクセス指定子です。

主な特徴は、次のとおりです。

  • 宣言元のクラス内部からアクセスできる
  • 派生クラスから条件付きでアクセスできる
  • 通常のクラス外部からはアクセスできない
  • friendからアクセスできる場合がある
  • 変数だけでなく、関数、コンストラクタ、デストラクタ、型などにも指定できる
  • メンバーに付けるprotectedprotected継承は別の機能である
  • 派生クラスでも、任意の基底クラス型オブジェクトを通じてアクセスできるわけではない
  • 基底クラスの内部状態を守るには、データをprivateにしてprotected関数を提供する方法が有効である

protectedは、継承を使った設計で便利な機能です。

ただし、特にデータメンバーをprotectedにすると、基底クラスと派生クラスの結合が強くなります。

基本的には内部データをprivateに保ち、派生クラスに必要な操作だけをprotectedメンバー関数として提供すると、安全で保守しやすいコードを作りやすくなります。

以上、C++のprotectedの意味と使い方についてでした。

最後までお読みいただき、ありがとうございました。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次