【问题标题】:Using make_shared with a protected constructor + abstract interface将 make_shared 与受保护的构造函数 + 抽象接口一起使用
【发布时间】: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();   
}

【问题讨论】:

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


【解决方案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。即使我的课程是模板化的。
猜你喜欢
  • 2010-11-08
  • 2013-11-13
  • 2012-10-06
  • 2013-08-29
  • 2011-05-30
  • 1970-01-01
  • 1970-01-01
  • 2015-11-17
  • 2021-06-10
相关资源
最近更新 更多