【问题标题】:Return unique_ptr with abstract class inside返回带有抽象类的 unique_ptr
【发布时间】:2021-09-23 13:30:36
【问题描述】:

我正在尝试封装引擎实现类的细节。为此,我返回抽象类的std::unique_ptr(在我的情况下为IEngine)而不是Engine。但由于编译错误,我无法做到这一点。我可以返回原始参考并且它可以工作,但是unique_ptr 可以吗?提前致谢。

class IEngine
{
public:
    virtual ~IEngine() = default;

    virtual void Start() = 0;
};

class Engine : public IEngine
{
public:
    void Start() override {}
};

class Car
{
    std::unique_ptr<Engine> m_engine;

public:

    std::unique_ptr<IEngine>& Get() { return m_engine; } // Here is compile error
};

int main()
{
    Car lambo;
}

【问题讨论】:

  • 注意:总是添加你的错误信息
  • 将成员设为私有但从 Get 返回非 const 引用的目的是什么?
  • 如果没有错误消息,我猜这个问题是在指针为std::unique_ptr&lt;Engine&gt; 时试图返回对std::unique_ptr&lt;IEngine&gt; 的引用。由于类型不同,此处不会发生自动转换。此外,在这种情况下,我也不认为返回对 unique_ptr 的引用是一个好主意。
  • unique_ptr&lt;Engine&gt; != unique_ptr&lt;IEngine&gt; 所以你不能只绑定对它的引用(从 Get 返回)
  • Get() 应该做什么?所有权转让?只允许(无限制)访问类中的对象(有点打破封装)

标签: c++ c++11 c++14 smart-pointers


【解决方案1】:

std::unique_ptr&lt;IEngine&gt; 是与std::unique_ptr&lt;Engine&gt; 不同的类型,因此您要求返回对临时对象的引用。

std::unique_ptr 唯一拥有它指向的对象,因此即使您删除了引用,从您可能想要的现有 std::unique_ptr&lt;Engine&gt; 创建 std::unique_ptr&lt;IEngine&gt; 也是不正确的保持不变。

你不应该在这里暴露std::unique_ptr。我不确定您是否应该在这里公开IEngine。我也很困惑为什么您需要在Car 中输入具体的Engine,但外部世界需要可变访问指向IEngine 的指针。

我希望得到类似的东西:

class Car
{
    std::unique_ptr<IEngine> m_engine;

public:

    void TurnIgnition() { m_engine->Start(); }
};

【讨论】:

    【解决方案2】:

    我正在尝试封装引擎实现类的细节。

    返回对私有成员的非常量引用很少是正确的做法。无论如何,它与数据封装相反。一旦调用者获得了参考,他们就可以随心所欲地使用它。返回非 const 引用对于方便访问方法(例如 std::vector::operator[])是有意义的。 std::vector::operator[] 的目的不是向调用者隐藏元素。还有其他方法可以得到它。而是std::vector::operator[] 是为了更方便地访问元素。不是封装。

    也不清楚为什么要从Get 返回unique_ptr。当不需要所有权转移时,不需要返回智能指针。

    我可以返回原始参考

    是的,很好:

    #include <memory>
    
    class IEngine
    {
    public:
        virtual ~IEngine() = default;
    
        virtual void Start() = 0;
    };
    
    class Engine : public IEngine
    {
    public:
        void Start() override {}
    };
    
    class Car
    {
        std::unique_ptr<Engine> m_engine;
    
    public:
    
        const IEngine& Get() { return *m_engine; } // Here is compile error
    };
    
    int main()
    {
        Car lambo;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-16
      • 2022-01-24
      • 2010-12-13
      • 2021-11-12
      • 1970-01-01
      相关资源
      最近更新 更多