基本クラスに静的ファクトリ メソッドがあります。いくつかの理由により、各派生クラスをこのファクトリ メソッドによってインスタンス化する必要があるため、これらのクラスはすべて保護された ctor を持っています。
実際の状況では、Create 関数はエラー処理と共に追加のロジックを実行します。
class Base
{
public:
virtual ~Base() {}
template <typename T>
static void Create(std::unique_ptr<T>& pOut)
{
pOut = std::unique_ptr<T>(new T);
// ...
}
protected:
Base() {}
};
class Derived : public Base
{
protected:
Derived() {}
};
int main()
{
std::unique_ptr<Derived> ptr;
Derived::Create(ptr);
}
保護されたctorにアクセスできないため、そのコードは明らかにコンパイルされません。
prog.cc: In instantiation of 'static void Base::Create(std::unique_ptr<_Tp>&) [with T = Derived]':
prog.cc:33:24: required from here
prog.cc:17:35: error: 'Derived::Derived()' is protected within this context
17 | pOut = std::unique_ptr<T>(new T);
| ^~~~~
prog.cc:26:5: note: declared protected here
26 | Derived() {}
| ^~~~~~~
最も一般的と思われる最初の解決策は、派生クラスでのフレンド宣言です。しかし、それは機能しますが、私はそれが好きではありません:
- 各派生クラスにそのような宣言を追加する必要があります
- これは友達です
class Derived : public Base
{
protected:
Derived() {}
friend void Base::Create<Derived>(std::unique_ptr<Derived>&);
};
より一般的なアプローチを考えて、私は次のようなことを試みていました:
template <typename T>
static void Create(std::unique_ptr<T>& pOut)
{
static_assert(std::is_base_of_v<Base, T>, "T should be Base-family class.");
class CreateHelper : public T
{
public:
static void InternalCreate(std::unique_ptr<T>& pOut)
{
pOut = std::unique_ptr<CreateHelper>(new CreateHelper);
// ...
}
};
CreateHelper::InternalCreate(pOut);
}
それは機能しますが、私には奇妙に見えます:
- 実際のポインタ型は CreateHelper ですが、この関数の外ではわかりません
- このアプローチでは、基本クラスへのポインターを使用するため、基本ファミリが多態的である必要があります (この条件は常に満たされている必要があるようですが、それでも言及する価値があります)。
私の質問は
- 最後のアプローチについてどう思いますか?
- それは悪いデザインと見なされますか?