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

发布于 2024-09-15 10:52:01 字数 1710 浏览 7 评论 0原文

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

Given an abstract interface and an implementation derived from that interface, where constructors are protected (creation of these objects only being available from a class factory - to implement a DI pattern), how can I make use of make_shared in the factory function?

For example:

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 obviously cannot access the protected constructor in InterfaceImpl, or indeed in IInterface, giving me the following error


error C2248: 'InterfaceImpl::InterfaceImpl' : cannot access protected member declared in class 'InterfaceImpl'

So reading here (question: How to make boost::make_shared a friend of my class), I tried putting the following into the implementation class:


friend std::shared_ptr<InterfaceImpl> std::make_shared<InterfaceImpl>();

It still wouldn't compile. So then I put another one into the IInterface class too. Still no joy. What have I done wrong here?

EDIT: Full source file used to compile, with "friend"...

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

孤独难免 2024-09-22 10:52:01

使用 VC10,您链接到的解决方案不起作用 - InterfaceImpl 实例的构造不会发生在 make_shared 中,而是发生在 std 中的内部类型中::tr1::_Ref_count_obj::_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 -习语

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;
}

With VC10 the solution you linked to doesn't work - the construction of the instance of InterfaceImpl doesn't happen in make_shared, but in an internal type in std::tr1::_Ref_count_obj<Ty>::_Ref_count_obj(void).

I'd just make the Create() function a friend in your case and not use 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());
}

... or use a custom make_shared() implementation that you actually can befriend without relying on ugly implementation details.

An alternative would be to use something like this 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;
}
雅心素梦 2024-09-22 10:52:01

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

friend class std::tr1::_Ref_count_obj<TheClassManagedByTheShared_Ptr>;

或者在您的情况下:

friend class std::tr1::_Ref_count_obj<InterfaceImpl>;

这适用于 VS2010 中的 Microsoft 编译器,但看起来它可能是特定于环境的,因为它不适用于 gcc Linux。对于 gcc,std::tr1 命名空间不存在,因此它必须特定于 std 库的 Microsoft 实现。

我的正常工作环境是 Intel 12.1 编译器,它似乎有一个错误,根本不检查访问权限,并且在没有任何友元声明的情况下愉快地构建代码。

To the original question, std::make_shared<...>() does not directly instantiate your class, so providing friend access to it yields no benefit, as you found. You can simply provide friend access to the code that does directly use your protected constructor as follows:

friend class std::tr1::_Ref_count_obj<TheClassManagedByTheShared_Ptr>;

or in your case:

friend class std::tr1::_Ref_count_obj<InterfaceImpl>;

This works with the Microsoft compiler in VS2010, but it looks like it may be environment specific as it does not work with gcc on Linux. With gcc the std::tr1 namespace does not exist, so it must be specific to the Microsoft implementation of std library.

My normal working environment is the Intel 12.1 compiler, which appears to have a bug that does not check for access at all, and happily builds code without any friend declaration.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文