今日、私はC++コードでprotected
メソッドを基本的に使用しないことに気付きました。親の非パブリックメソッドを呼び出す必要性を感じることはほとんどないからです。テンプレートメソッドパターンではJava=でprotectedを使用していますが、C++ではプライベートメソッドをオーバーライドできるため、protected
も必要ありません。
それでは、C++コードでprotected
メソッドを使用したい実際のシナリオは何ですか?
(一般に、実装の継承はあまり好きではないことに注意してください。これは多くのことを説明するかもしれません...)
ここに例があります
class Base {
public:
// other members ...
protected:
~Base() { }
};
非ポリモーフィック基本クラスとして使用されます。ただし、デストラクタにアクセスできないため、ユーザーはdelete baseptr;
を呼び出すことができません。仮想デストラクタがないため、人々にそれを許可することは未定義の動作になります。ハーブによる "Virtuality" を参照してください。
私が頻繁に使用する1つの例は、オブジェクト階層の基本クラスで、保護されたロガーを持つことです。私のすべての基本クラスはロガーにアクセスする必要がありますが、それを公にアクセス可能にする理由はありません。
また、テンプレートパターンを使用していて、基本クラスに実行前メソッドまたは実行後メソッドがある場合は、オーバーライドするメソッドから基本実装を呼び出すことができます。ベースがプライベートのみである(そしてC++でも上書きできる)場合、オーバーライドするメソッドからベース実装を呼び出すことはできません。
過去に使用した例です。プロテクトメソッドは、実装固有の機能を提供するのに最適ですが、基本クラスで適切に追跡することもできます。オーバーライド可能な初期化関数を提供するが、初期化されているかどうかを判断するための状態も持っている必要がある基本クラスを検討してください。
_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()
を呼び出そうとしない場合を除いて、誰でもそれを呼び出すことができるという事実(これをここで保護することができ、保護されたメソッドを使用するもう1つの理由!)私は仮想保護されたメンバーを利用するクラスをずっと好みます:
_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
_
新しいクラスでは、すべての初期化は引き続き派生クラスに委任されています。スローされた例外が提供された場合、メソッドが発生すると言う「このクラスは初期化されています」というコントラクトを維持します。
他の多くの機能と同様に、protected
を使用すると、カプセル化をある程度拡張できます。純粋なOOの概念を破ることは、通常、いくつかの理由で行われます
inline
と考えてください)、friend
を使用すると、クラスのメンバーへのアクセスを数人の友達に制限できます)protected
は、そのボックス内のツールの1つにすぎません。派生クラスに、一般に公開しないクラスの一部へのアクセスを許可する場合に使用できます。
私が使用した1つのケースは、クラスのすべてのコンストラクタをprotected
にして、基本的にそのクラスを抽象化することです(派生クラスのオブジェクトのサブオブジェクトとして以外はインスタンス化できません)。 。
おそらくそれは悪いデザインでしたが、私はこのようなもののためにそれを持ちました:
_// 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()
を呼び出すことでシグナルをトリガーできます。しかし、それだけで信号を処理できるため、信号自体は非公開のままにされました。トリガーされた関数のみがトリガーされ、何もトリガーされないため、トリガー関数が保護されました。
「パブリックメソッド」:クラスはこれを行うことができます。 「保護されたメソッド」:クラスがこれを行う方法「プライベートメソッド」:クラスでこれを行う方法。
// 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();
}
それで、新しい料理人(開発者)がファストフードレストランに到着しました。あなたはそれを教え、ハンバーガーを販売し(公的な方法)、ハンバーガーを準備する方法(保護された方法)を行いますが、「特許を取得した」秘密のレシピソースを自分に教えてください。