1

基本クラスに静的ファクトリ メソッドがあります。いくつかの理由により、各派生クラスをこのファクトリ メソッドによってインスタンス化する必要があるため、これらのクラスはすべて保護された 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() {}
      |     ^~~~~~~

最も一般的と思われる最初の解決策は、派生クラスでのフレンド宣言です。しかし、それは機能しますが、私はそれが好きではありません:

  1. 各派生クラスにそのような宣言を追加する必要があります
  2. これは友達です
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);
    }

それは機能しますが、私には奇妙に見えます:

  1. 実際のポインタ型は CreateHelper ですが、この関数の外ではわかりません
  2. このアプローチでは、基本クラスへのポインターを使用するため、基本ファミリが多態的である必要があります (この条件は常に満たされている必要があるようですが、それでも言及する価値があります)。

私の質問は

  1. 最後のアプローチについてどう思いますか?
  2. それは悪いデザインと見なされますか?
4

1 に答える 1