是否可以制作非虚拟创建方法


#include <memory>
class Base
{
    std::shared_ptr<Base> create() const; // Returns a default constructed object
}

假设从Base派生到任何程度的所有成员都是可复制的,默认可构造的。我想要

std::shared_ptr<Base> create() const;

创建适当动态类型的对象的方法,但我不想使用样板代码。

有没有可能制作

std::shared_ptr<Base> create() const;

静态绑定,但在内部找到正确的类型并使用 Default 构造函数创建对象?可能使用 C++11。

create()函数可能应该是静态的,因为您还没有实例。但是没有参数,你就不能做你想做的事......当然,除非您使用模板:

class Base
{
public:
    template<typename T>
    static std::shared_ptr<Base> create() const
    {
        return std::shared<Base>(new T);
    }
};

然后以这种方式使用它:

std::shared_ptr<Base> ptr(Base::create<Foo>());

或者,如果您愿意:

std::shared_ptr<Base> ptr(Foo::create<Foo>());

理想情况下,您有一个静态的,也许是一个非静态的create()函数。有一种聪明的方法可以实现这一点。

  1. 定义SuperBase类。它需要一个虚拟析构函数和一个纯虚拟create()函数。你将使用指向此类的指针/引用来实现正常的后期绑定 OOP 行为。

  2. 定义从 SuperBase 继承的 Base类模板。 Base 的模板参数将是 Derived 类的类型。 Base还将有一个特征类模板,其中包含一个名为 create() 的静态函数。此静态create()函数将使用 new 创建一个默认对象。使用 trait 的 create() 函数,Base将定义static_create()和纯虚SuperBase::create()函数。

  3. 通过继承Base<Derived>来实现Derived

如果您知道您正在使用派生类型,则可以编写Derived::create()以静态创建新类型。如果没有,则始终可以使用实例的create()方法。多态性不会中断,因为SuperBase将具有您需要/想要的多态接口 - Base<D>只是一个自动定义static_create()create()函数的帮助程序类,因此您通常不会直接使用Base<D>

示例代码如下所示:

#include <memory>
#include <iostream>
class SuperBase
{
  public:
    virtual ~SuperBase() = default;
    virtual std::shared_ptr<SuperBase> create() const = 0;
};
template <typename T>
struct Base_Traits
{
  static T* create()
  {
    return new T;
  }
};
template <typename Derived, typename Traits=Base_Traits<Derived>>
class Base : public SuperBase
{
  public:   
    // Define a static factory function...
    static std::shared_ptr<SuperBase> static_create()
    {
      return std::shared_ptr<SuperBase>{Traits::create()};
    }
    // Define pure virtual implementation...
    std::shared_ptr<SuperBase> create() const override
    {
      return static_create();
    }
};
class Derived : public Base<Derived>
{
};
int main()
{
  auto newone = Derived::static_create();  // Type known @ compile time
  auto anotherone = newone->create();      // Late binding; type not known @ compile time
}

最新更新