保護されたメソッドの実際のシナリオ


14

今日、私は基本的protectedにC ++コードでメソッドを使用しないことに気付きました。親の非パブリックメソッドを呼び出す必要性をほとんど感じないからです。テンプレートメソッドパターンではJavaでprotectedを使用していますが、C ++でプライベートメソッドをオーバーライドできるため、ここでも必要protectedありません。

それではprotected、C ++コードでメソッドを使用する実際のシナリオは何ですか?

(私は一般的に実装の継承があまり好きではないことに注意してください、それは多くを説明するかもしれません...)

回答:


12

ここに例があります

class Base {
public:
  // other members ...

protected:
  ~Base() { }
};

非多態性の基本クラスとして使用されます。しかしdelete baseptr;、デストラクタにアクセスできないため、ユーザーはその上で呼び出すことができません。仮想デストラクタがないため、ユーザーがそれを実行できるようにすることは未定義の動作になります。ハーブによる「仮想性」を参照してください。


1
元気ですか?なぜこれがダウン投票されたのですか?それは完全に合理的です。あなたがそれを理解しないならば、尋ねてください。間違っていると思う場合は、説明してください。私たちはあなたの洞察から学ぶためにここにいます。
sbi

なぜ-1ですか?これが私が最初に考えたものです。
-GManNickG

1
コンストラクタとデストラクタは、私が見た唯一の用途です。gccは、このデストラクタが非仮想であるという警告を引き続き出力します。
マチューM.

+1また、protectedメソッドを使用して、書籍に関するいくつかのアドバイスを適用します。パブリック仮想関数ではなく、保護された仮想関数を持つパブリックインターフェイスを使用します。
クライム

3

私が頻繁に使用する1つの例は、オブジェクト階層の基本クラスで、ロガーが保護されることです。すべての基本クラスはLoggerにアクセスする必要がありますが、一般にアクセスできるようにする理由はありません。

また、テンプレートパターンを使用しており、基本クラスに実行前または実行後メソッドがある場合、オーバーライドメソッドから基本実装を呼び出すことができます。ベースがプライベートのみである(そしてC ++でまだ上書きできる)場合、オーバーライドメソッドからベース実装を呼び出すことはできません。


1
テンプレートパターンは、基本クラスメソッドを呼び出す必要がないということではありませんか?
sbi

ポイントをとったが、基本クラスのメソッドを呼び出す必要がないということは「すべて」とは言いません。多くの状況では、複数のレベルを持つテンプレートパターンを実装するオブジェクト階層があり、それぞれのレベルでわずかに機能/チェックが追加されます。これらの場合、Protectedメソッドが必要になります。
-bryanatkinson

1

過去に使用した例です。保護されたメソッドは、実装固有の機能を提供するのに最適ですが、基本クラスが適切に追跡できるようにします。オーバーライド可能な初期化関数を提供する基本クラスを検討しますが、初期化されたかどうかを判断する状態も必要です。

class Base
{
private:
    bool m_bInitialized;
public:
    virtual void Initialize() = 0;

    void setInitialized() { m_bInitialized = true; };
    bool isInitialized() const { return m_bInitialized; };
}; // eo class Base

ここではすべてが順調です。派生クラスが呼び出すsetInitialized()ことを気にしない場合を除いて、誰もが呼び出すことができるという事実(これをここで保護することができ、保護されたメソッドを使用する別の理由!)仮想保護されたメンバーを使用するクラスが非常に好きです:

class Base
{
private: 
    bool m_bInitialized;

protected:
    virtual void InitializeImpl() = 0;

public:

    void Initialize()
    {
        InitializeImpl();
        m_bInitialized = true;
    }; // eo Initialize

    bool isInitialized() const { return m_bInitialized; };
}; // eo class Base

新しいクラスでは、すべての初期化は派生クラスに委任されます。例外がスローされた場合、メソッドが発生すると言う「このクラスは初期化されています」コントラクトを維持します。


0

他の多くの機能と同様に、protectedカプセル化をある程度拡張できます。純粋なオブジェクト指向の概念を破るには、通常いくつかの理由があります

  1. より良いパフォーマンスを達成する(考えるinline
  2. コードを理解しやすくし、皮肉なことに、
  3. カプセル化の改善(friendクラスメンバーへのアクセスを数人の友人に制限できます)

そして protected、そのボックスのツールの1つにすぎません。派生クラスに、一般の人々から隠されるべきクラスの一部へのアクセスを許可したい場合に使用できます。

私がそれを使用した1つのケースは、クラスのすべてのコンストラクタをprotected作成し、基本的にそのクラスを抽象化することです(派生クラスのオブジェクトのサブオブジェクトとして以外はインスタンス化できません)。


0

おそらくそれは悪いデザインでしたが、私はこのようなもののためにそれを持っていました:

// much simplified, of course
class input_device // base class
{
public:
    virtual ~input_device() {}

    // normally would be private with public caller, etc.
    virtual void update() = 0; 

    template <typename Func>
    void register_callback(Func func)
    {
        mButtonPressSignal.connect(func);
    }

protected:
    void trigger_signal(unsigned button)
    {
        mButtonPressSignal(button);
    }

private:
    boost::signals2::signal<void(unsigned)> mButtonPressSignal;
};

の派生クラスは、をupdate()呼び出すことで信号をトリガーできtrigger_signal()ます。しかし、それで信号を処理できるのはそれだけなので、信号自体は非公開のままでした。トリガー関数は、派生クラスのみがトリガーできる必要があり、何もトリガーできないため、保護されました。


0

「パブリックメソッド」:クラスはこれを行うことができます。「保護されたメソッド」:クラスがこれを行う方法。「プライベートメソッド」:クラスはこれをどのように行うことができますが、「私は妄想的で、どのように私がそれを行うかを誰にも知られたくない」。

// burguers.hpp

class BurguerClass {
  private: void addSecretRecipeSauce();  

  protected: virtual void addBread();  
  protected: virtual void addSalad();  
  protected: virtual void addMeat();
  protected: virtual void addExtraIngredients();

  public: virtual void makeBurguer();  
}

class CheeseBurguerClass: public BurguerClass {
  protected: override void addBread();  
  protected: override void addSalad();  
  protected: override void addMeat();
  protected: override void addExtraIngredients();

  protected: virtual void addCheese();

  public: override void makeBurguer();
}

class RanchStyleBurguerClass: public BurguerClass {
  protected: override void addBread();  
  protected: override void addSalad();  
  protected: override void addMeat();
  protected: override void addExtraIngredients();

  public: override void makeBurguer();
}

class EastCoastVegetarianStyleBurguerClass: public BurguerClass {
  protected: override void addBread();  
  protected: override void addSalad();  
  protected: override void addMeat();
  protected: override void addExtraIngredients();

  public: override void makeBurguer();
}

そのため、新しい料理人(開発者)がファーストフードレストランに到着します。あなたはそれを教え、ブルガー(パブリックメソッド)、ブルガーの準備方法(保護されたメソッド)を販売しますが、「特許を取得した」秘密のレシピソースを自分に保ちます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.