将make_shared与受保护的构造函数+抽象接口一起使用

时间:2010-08-22 13:29:03

标签: c++ constructor protected visual-c++-2010 make-shared

给定一个抽象接口和从该接口派生的实现,其中构造函数受到保护(这些对象的创建只能从类工厂中获得 - 实现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();   
}

2 个答案:

答案 0 :(得分:4)

使用VC10,您链接的解决方案不起作用 - InterfaceImpl实例的构建不会发生在make_shared中,而是发生在std::tr1::_Ref_count_obj<Ty>::_Ref_count_obj(void)中的内部类型中。< / p>

我只是将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;
}

答案 1 :(得分:4)

对于原始问题,std :: make_shared&lt; ...&gt;()不直接实例化您的类,因此提供朋友访问它不会产生任何好处,如您所发现的那样。您可以简单地向朋友提供对直接使用受保护构造函数的代码的访问权限,如下所示:

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编译器,它似乎有一个根本不检查访问权限的错误,并且很乐意在没有任何朋友声明的情况下构建代码。