我想实现应用程序中的某些对象只能通过调用名为“create”的静态方法来构造为shared_ptr。
当然,我可以直接在所有相关类中添加静态“create”方法。但是,这意味着我必须在几乎所有类中重复非常相似的代码。宏可能有效,但我认为这不太优雅。
我提出了一种替代方法,即从一个模板化的“BaseObject”类派生所有类,该类实现“create”方法并返回指针。这几乎可行,但是当其为受保护时,std::make_shared无法访问其子类的构造函数。
非解决方案是将子类构造函数设置为public(请参见下面的(1))。但是现在Foo可以正常构造,这将使整个点失去意义。另一种解决方案是将BaseObject设置为子类的友元,并直接使用shared_ptr(请参见下面的(2))。
这两种解决方案都给子类的实现者增加了额外的负担。因为他们必须找到另一种使构造函数非公开的方法或放置friend声明。第二种解决方案还有一个问题,就是不能使用更高效的make_shared。
我的问题是:是否有更好的方法来做到这一点?
当然,我可以直接在所有相关类中添加静态“create”方法。但是,这意味着我必须在几乎所有类中重复非常相似的代码。宏可能有效,但我认为这不太优雅。
我提出了一种替代方法,即从一个模板化的“BaseObject”类派生所有类,该类实现“create”方法并返回指针。这几乎可行,但是当其为受保护时,std::make_shared无法访问其子类的构造函数。
非解决方案是将子类构造函数设置为public(请参见下面的(1))。但是现在Foo可以正常构造,这将使整个点失去意义。另一种解决方案是将BaseObject设置为子类的友元,并直接使用shared_ptr(请参见下面的(2))。
这两种解决方案都给子类的实现者增加了额外的负担。因为他们必须找到另一种使构造函数非公开的方法或放置friend声明。第二种解决方案还有一个问题,就是不能使用更高效的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;
}
更新:
在此刻,他们的传递密钥习语似乎为我提供了最佳解决方案:
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::create作为shared_ptr创建Foo对象才有可能。
- 无需在Foo中添加复杂的友元声明。
- std::make_shared仍然有效。
这种解决方案唯一的问题是要求将“Key”作为构造函数的第一个参数。但我可以接受这个问题。