强制 class 只在工厂内施工

Force class construction exclusively inside factory

我想知道是否有人知道强制 class 层次结构只能由工厂构造的方法,有效地禁止在该工厂外直接使用 std::make_shared

在下面的示例中,我将 Node 作为基础 class 和 SceneNode 作为许多派生 classes。 Node 包含一个静态成员函数 create() 它应该是工厂并且是创建 Node[= 的新实例的唯一方法22=]-派生的classes.

#include <iostream>
#include <memory>

class Node {
  public:
    template <class T, class... Args>
    static std::shared_ptr<T> create(Args&&... args)
    {
      static_assert(std::is_base_of<Node, T>::value, "T must derive from Node");
      std::shared_ptr<T> node = std::make_shared<T>(std::forward<Args>(args)...);
      return node;
    }

  protected:
    Node() {}

};

class SceneNode : public Node {
  public:
    SceneNode() : Node()
    {
    }
};

int main() {
    auto a = Node::create<SceneNode>(); // Should be the only way
    auto b = std::make_shared<SceneNode>(); // Should be forbidden
}

使您的工厂成为唯一 class 能够实例化给定 class 的 classic 方法是使您的 class 构造函数私有,并使您的工厂你 class 的朋友:

class Foo
{
    friend class FooFactory;

private:
    Foo() = default;
};

class FooFactory
{
public:
    static Foo* CreateFoo() { return new Foo(); }
    static void DestroyFoo(Foo* p_toDestroy) { delete p_toDestroy; }
};

int main()
{
    // Foo foo; <== Won't compile
    Foo* foo = FooFactory::CreateFoo();
    FooFactory::DestroyFoo(foo);
    return 0;
}

编辑(有一些继承):

#include <type_traits>

class Foo
{
    friend class FooBaseFactory;

protected:
    Foo() = default;
};

class Bar : public Foo
{
    friend class FooBaseFactory;

protected:
    Bar() = default;
};

class FooBaseFactory
{
public:
    template <typename T>
    static T* Create()
    {
        static_assert(std::is_base_of<Foo, T>::value, "T must derive from Foo");
        return new T();
    }

    template <typename T>
    static void Destroy(T* p_toDestroy)
    { 
        static_assert(std::is_base_of<Foo, T>::value, "T must derive from Foo");
        delete p_toDestroy;
    }
};

int main()
{
    // Foo foo; <== Won't compile
    Foo* foo = FooBaseFactory::Create<Foo>();
    FooBaseFactory::Destroy<Foo>(foo);

    // Bar bar; <== Won't compile
    Bar* bar = FooBaseFactory::Create<Bar>();
    FooBaseFactory::Destroy<Bar>(bar);
    return 0;
}

此问题的一个解决方案是创建一个只有工厂可以实例化的类型,并且需要 class 的实例来构造基类型。您可以建立一个约定,其中从 Node 派生的类型的第一个构造函数参数是该类型的值或对该类型的引用,该类型被提供给 Node 的构造函数。由于其他任何人都不可能拥有 NodeKey 用户无法在不通过工厂的情况下实例化从 Node 派生的任何内容。

#include <memory>
#include <utility>

// Class that can only be instantiated by the factory type
class NodeKey {
private:
    NodeKey() {};
    friend class Factory;
};

class Factory {
public:
    template<class T, class ... Args>
    auto make(Args&&... args) {
        auto ptr = std::make_shared<T>(NodeKey{}, std::forward<Args>(args)...);
        // Finish initializing ptr
        return ptr;
    }
};

class Node {
public:
    // Can only be called with an instance of NodeKey
    explicit Node(const NodeKey &) {};
};

class Foo : public Node {
public:
    // Forwards the instance 
    explicit Foo(const NodeKey & key) : Node(key) {};
};

int main()
{
    Factory factory;
    auto f = factory.make<Foo>();
}