将 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&lt;IInterface> Create();     
    virtual void Method() = 0;
;

class InterfaceImpl : public IInterface
    
public:     
    virtual void Method() 

protected:    
    friend std::shared_ptr&lt;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&lt;Ty&gt;::_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++ 中将返回值移动语义与受保护的复制构造函数一起使用?

如何将 ACL 与受保护的资源连接起来?

通过 make_unique/make_shared 调用 initializer_list 构造函数

将 WordPress iOS 应用程序与受 Shibboleth 保护的 WordPress 配合使用

受保护的内部属性与受保护的属性和 Resharper

公共与受保护