5

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

所以在这里阅读(问题:如何使 boost::make_shared 成为我班的朋友),我尝试将以下内容放入实现类中:


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();   
}
4

2 回答 2

4

使用 VC10,您链接到的解决方案不起作用 - 实例的构造InterfaceImpl不会发生在 中make_shared,而是在std::tr1::_Ref_count_obj<Ty>::_Ref_count_obj(void).

我只是在你的情况下制作Create()函数 a而不是使用friendmake_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;
}
于 2010-08-22T13:59:21.403 回答
4

对于最初的问题, 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 编译器,它似乎有一个根本不检查访问的错误,并且在没有任何朋友声明的情况下愉快地构建代码。

于 2012-12-11T20:38:17.083 回答