なぜコンストラクターが保護されていると宣言するのですか?コンストラクターは、スタックでの作成を許可しないためにプライベートとして宣言されていることを知っています。
クラスが(として意図されている)抽象クラスである場合、保護されたコンストラクターは正確です。そのような状況では、オブジェクトをクラスからインスタンス化するのではなく、それを継承するためにのみ使用します。
特定の構築パラメーターのセットを派生クラスに制限する必要がある場合など、他のユースケースもあります。
非パブリックコンストラクターは、コンストラクターだけでは保証できない構築要件がある場合に役立ちます。たとえば、コンストラクターの直後に初期化メソッドを呼び出す必要がある場合、またはオブジェクトをコンテナー/マネージャーオブジェクトに登録する必要がある場合、これはコンストラクターの外部で実行する必要があります。コンストラクターへのアクセスを制限し、ファクトリメソッドのみを提供することにより、ユーザーが受け取るインスタンスがすべての保証を確実に満たすようにできます。これは、シングルトンの実装にもよく使用されます。これは、クラスが作成する別の保証です(単一のインスタンスのみが存在することを保証します)。
コンストラクタをプライベートではなく保護する理由は、子では継承できるように、プライベートではなく他のメソッドまたはフィールドを保護する理由と同じです。おそらく、派生クラスのインスタンスへの参照を返す、基本クラスのパブリックな非仮想ファクトリメソッドが必要な場合があります。派生クラスは明らかに親コンストラクタへのアクセスを必要としますが、それでもファクトリの外部で作成することは望ましくありません。
1つの用途は工場のパターンです
保護されたコンストラクターを使用すると、そのメソッドのいずれも純粋仮想ではない場合に、クラスを効果的に抽象化できます。
フレンドクラスはオーバーライドせずに使用できるため、C++の意味では抽象的ではありませんが、これらを宣言する必要があります。
副作用のあるファクトリメソッドの場合。
class mine {
private:
mine () {};
protected:
mine(int id) : m_id(id) {};
int m_id;
static int m_count;
public:
static mine* CreateOneOfMe() {
return mine(m_count++);
}
int GetId() { return m_id; }
};
これにより、クラスのインスタンスが作成され、各インスタンスが一意の増分整数IDを持つことが保証されます。使用するコンストラクタがデフォルトでない場合は、デフォルトも非表示にする必要があることに注意してください。
保護されたコンストラクターは、派生メンバーのみがそのコンストラクターを使用してクラスのインスタンス(および派生インスタンス)を構築できることを意味します。これは少し鶏と卵に聞こえますが、クラスファクトリを実装するときに役立つことがあります。
サブクラスに、インスタンス化機能が直接アクセスできないようにする必要があるコンストラクターを使用できるようにします。
これを使用して、作成できるクラスを制限できます。たとえば、次のとおりです。
class Level
{
private:
Level();
¨Level();
friend class LevelManager;
};
そのインスタンスを作成できる唯一のクラスはLevelManagerクラスです。したがって、LevelインスタンスがLevelManagerで作成されていることを常に知ることができます。
保護されたコンストラクターの1つの使用法は、CRTPパターンを実装することです。以下のコードを参照してください。
#include <iostream>
#include <assert.h>
template <class T>
class ComparableMixin {
public:
bool operator !=(ComparableMixin &other) {
return ~(*static_cast<T*>(this) == static_cast<T&>(other));
}
bool operator <(ComparableMixin &other) {
return ((*(this) != other) && (*static_cast<T*>(this) <= static_cast<T&>(other)));
}
bool operator >(ComparableMixin &other) {
return ~(*static_cast<T*>(this) <= static_cast<T&>(other));
}
bool operator >=(ComparableMixin &other) {
return ((*static_cast<T*>(this) == static_cast<T&>(other)) || (*(this) > other));
}
protected:
ComparableMixin() {}
};
class Integer: public ComparableMixin<Integer> {
public:
Integer(int i) {
this->i = i;
}
int i;
bool operator <=(Integer &other) {
return (this->i <= other.i);
}
bool operator ==(Integer &other) {
return (this->i == other.i);
}
};
int main() {
Integer i(0) ;
Integer j(1) ;
//ComparableMixin<Integer> c; //compilation error!
assert (i < j );
assert (i != j);
assert (j > i);
assert (j >= i);
return 0;
}