将 make_shared 与受保护的构造函数 + 抽象接口一起使用
Posted
技术标签:
【中文标题】将 make_shared 与受保护的构造函数 + 抽象接口一起使用【英文标题】:Using make_shared with a protected constructor + abstract interface 【发布时间】:2011-04-02 06:45:31 【问题描述】:给定一个抽象接口和从该接口派生的实现,其中构造函数受到保护(这些对象的创建只能从类工厂获得 - 以实现 DI 模式),我如何在工厂函数中使用 make_shared ?
例如:
class IInterface
public:
virtual void Method() = 0;
;
class InterfaceImpl : public IInterface
public:
virtual void Method()
protected:
InterfaceImpl()
;
std::shared_ptr<IInterface> Create()
std::shared_ptr<IInterface> object = std:: make_shared<InterfaceImpl>();
return object;
make_shared 显然无法访问 InterfaceImpl 或 IInterface 中的受保护构造函数,给我以下错误
error C2248: 'InterfaceImpl::InterfaceImpl' : cannot access protected member declared in class 'InterfaceImpl'
所以在这里阅读(问题:How to make boost::make_shared a friend of my class),我尝试将以下内容放入实现类:
friend std::shared_ptr<InterfaceImpl> std::make_shared<InterfaceImpl>();
它仍然无法编译。因此,我也将另一个放入 IInterface 类。仍然没有喜悦。我在这里做错了什么?
编辑:用于编译的完整源文件,带有“朋友”...
#include <memory>
class IInterface
public:
friend std::shared_ptr<IInterface> Create();
virtual void Method() = 0;
;
class InterfaceImpl : public IInterface
public:
virtual void Method()
protected:
friend std::shared_ptr<IInterface> Create();
InterfaceImpl()
;
std::shared_ptr<IInterface> Create()
std::shared_ptr<IInterface> object = std::make_shared<InterfaceImpl>();
return object;
void main()
std::shared_ptr<IInterface> i = Create();
【问题讨论】:
我猜那是VC10? GCC 顺便说一句,只要你和make_shared()
成为朋友就没有问题。
这是 VS2010,它实际上给出了一个警告(错误地 - 在这里详细说明:connect.microsoft.com/VisualStudio/feedback/details/321690/…)。
【参考方案1】:
使用 VC10,您链接到的解决方案不起作用 - InterfaceImpl
实例的构造不会发生在 make_shared
中,而是发生在 std::tr1::_Ref_count_obj<Ty>::_Ref_count_obj(void)
的内部类型中。
在你的情况下,我只是将Create()
函数设为friend
,不使用make_shared()
:
class InterfaceImpl : public IInterface
// ...
protected:
friend std::shared_ptr<IInterface> Create();
InterfaceImpl()
;
std::shared_ptr<IInterface> Create()
return std::shared_ptr<IInterface>(new InterfaceImpl());
...或使用自定义的make_shared()
实现,您实际上可以结识它,而无需依赖丑陋的实现细节。
另一种方法是使用类似pass-key-idiom:
class InterfaceImpl : public IInterface
public:
class Key
friend std::shared_ptr<IInterface> Create();
Key()
;
InterfaceImpl(const Key&)
;
std::shared_ptr<IInterface> Create()
std::shared_ptr<IInterface> object =
std::make_shared<InterfaceImpl>(InterfaceImpl::Key());
return object;
【讨论】:
恐怕也不编译! @rob: 嗯,发帖前我在 VC10 中测试过。您是否使用不同的代码进行测试? 也许我错过了什么。这是我正在编译的代码(跟进“答案”,因为评论不允许代码看起来......!)...... @rob:不要发布 "answers" 此类问题,而是编辑问题以进行更新。 @rob:您的更新仍然使用make_shared()
- 尝试从我的回答中复制/粘贴Create()
。【参考方案2】:
对于原始问题, std::make_shared<...>() 不会直接实例化您的类,因此正如您所发现的,向朋友提供对它的访问不会产生任何好处。您可以简单地为直接使用受保护构造函数的代码提供朋友访问权限,如下所示:
friend class std::tr1::_Ref_count_obj<TheClassManagedByTheShared_Ptr>;
或者在你的情况下:
friend class std::tr1::_Ref_count_obj<InterfaceImpl>;
这适用于 VS2010 中的 Microsoft 编译器,但它看起来可能是特定于环境的,因为它不适用于 Linux 上的 gcc。使用 gcc,std::tr1 命名空间不存在,因此它必须特定于 std 库的 Microsoft 实现。
我的正常工作环境是 Intel 12.1 编译器,它似乎有一个根本不检查访问的错误,并且在没有任何朋友声明的情况下愉快地构建代码。
【讨论】:
使用 VC2013。即使我的课程是模板化的。以上是关于将 make_shared 与受保护的构造函数 + 抽象接口一起使用的主要内容,如果未能解决你的问题,请参考以下文章
是否可以在 C++ 中将返回值移动语义与受保护的复制构造函数一起使用?
通过 make_unique/make_shared 调用 initializer_list 构造函数