c++ - 通过基类 'create' 方法仅将对象创建为共享指针

标签 c++ c++11 constructor shared-ptr

我试图实现我的应用程序中的某些对象只能通过调用名为“create”的静态方法构造为 shared_ptr。

当然,我可以通过直接将静态“create”方法添加到所有相应的类来做到这一点。但是,这意味着我必须在几乎所有类(class)中重复非常相似的代码。宏可以工作,但我觉得这不是很优雅。

我想出了一种替代方法,即从实现“create”方法并返回指针的模板化“BaseObject”类派生所有类。这几乎可以工作,除了 std::make_shared 在 protected 时无法访问其子类的构造函数。

非解决方案是将子类构造函数公开(参见下面示例中的 (1))。但是现在 Foo 可以再次正常构造,这将破坏整个点。另一种解决方案是在子类中将 BaseObject 设为友元并直接使用 shared_ptr(参见示例中的 (2))。

这两种解决方案都给子类的实现者带来了额外的负担。因为他们必须找到一种使构造函数非公开的替代方法或放置友元声明。 (2) 解决方案存在无法使用更高效的 make_shared 的额外问题。

我的问题:有更好的方法吗?

template<class T>
class BaseObject
{
public:
    typedef std::shared_ptr<T> SharedPtr;

    template<class... Args>
    static typename BaseObject<T>::SharedPtr create(Args&&... args)
    {
        return std::make_shared<T>(args...);
        //return std::shared_ptr<T>(new T(args...)); (2)
    }
};

class Foo : public BaseObject<Foo>
{
//friend BaseObject<Foo>; (2)

protected: //public (1)
    Foo(int a = 0) : m_foo(a) {}

private:
    int     m_foo;
};


int main(int argc, char* argv[])
{
    Foo::SharedPtr bla = Foo::create(1);
    return 0;
}

更新:

此时,他们的 pass-key 习语似乎为我提供了最好的解决方案:

template<class T>
class BaseObject
{
public:
    typedef std::shared_ptr<T> SharedPtr;

    class Key
    {
        friend class BaseObject<T>;
        Key() {}
    };

    template<class... Args>
    static typename BaseObject<T>::SharedPtr create(Args&&... args)
    {
        return std::make_shared<T>(Key(), args...);
    }
};

class Foo : public BaseObject<Foo>
{
public:
    Foo(BaseObject<Foo>::Key, int a = 0) : m_foo(a) {}

private:
    int     m_foo;
};

好东西:

  • 只能通过以下方式将 Foo 的对象创建为 shared_ptr Foo::创建。
  • 无需在 Foo 中添加复杂的友元声明。
  • std::make_shared 仍然有效。

此解决方案的唯一问题是要求将“Key”作为构造函数中的第一个参数。但我可以忍受。

最佳答案

更好是主观的,但我相信如果您将构造函数设为私有(private),并将 std::make_shared 设为友元函数,会更加直观。这样,唯一可以创建您的对象的函数就是 std::make_shared,您可以这样写

std::shared_ptr<Foo> ptr = std::make_shared<Foo>(12);

代替:

Foo::SharedPtr bla = Foo::create(1);

因此,任何 future 阅读您代码的人都可以在不实际查看 Foo 类的情况下理解您的意思。

更新

我已经尝试了我写的东西,但没有真正起作用。这是一个类似问题的答案,它很可能也适用于您的问题:

Using make_shared with a protected constructor + abstract interface

更新 2

这是让它工作的方法 (VC++2013)

#include <memory>

using namespace std;

class Foo
{
protected:
    Foo(int a = 0) : m_foo(a) {}

private:
    int     m_foo;

    friend  shared_ptr<Foo> make_shared<>();
    friend class _Ref_count_obj<Foo>;
};



int main()
{
  shared_ptr<Foo> foo = make_shared<Foo, int>(12);
  return 0;
}

_Ref_count_objmake_shared 内部使用,这就是为什么你也需要和它成为 friend 。

关于c++ - 通过基类 'create' 方法仅将对象创建为共享指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29881107/

相关文章:

java - 为什么我得到空对象数组的 NullPointerException 但该对象具有默认构造函数?

C++ 模板右值 Ctor 与 Const 引用 Ctor

c++ - 如何查找和比较字符数组的元素

c++ - 为什么允许这种转换?

c++ - 标准库对自 move 分配有什么保证?

C++ 空类或 typedef

c++ - ROS 订阅回调 - 使用 boost::bind 和成员函数

c++ - 使用文字为模板类型赋值

C++11 带小数秒的日期/时间

c++ - 为什么move构造函数不通过using声明继承