【问题标题】:Return a unique_ptr to polymorphic type将 unique_ptr 返回到多态类型
【发布时间】:2017-06-09 16:11:54
【问题描述】:

我试图通过从我的一些方法返回一个 unique_ptr 而不是原始指针来更安全一些。但是,在返回指向多态类型的唯一指针时,我有点困惑。

我们如何返回一个指向派生类类型的基类类型的唯一指针?

另外,作为次要问题 - 我是否使用移动构造函数正确地从基类创建派生类?

这是我的最小示例:

// Standard Includes
#include <exception>
#include <memory>
#include <string>
#include <sstream>

//--------------------------------------------------------------------------------------------------
class BaseResult
{
public:

    std::string m_x;

    virtual ~BaseResult() {};
};

class DerivedResult : public BaseResult
{
public:

    int m_y;

    DerivedResult()
        :
        BaseResult()
    {}

    DerivedResult(const DerivedResult & rhs)
        :
        BaseResult(rhs)
      , m_y       (rhs.m_y)
    {}

    DerivedResult(DerivedResult && rhs)
        :
        BaseResult(std::move(rhs))
      , m_y(rhs.m_y)
    {}

    DerivedResult(BaseResult && rhs)
        :
        BaseResult(std::move(rhs))
        , m_y()
    {
    }

    ~DerivedResult() {}
};

class BaseCalc
{
public:

    virtual ~BaseCalc() {}

    virtual std::unique_ptr<BaseResult> Calc() const
    {
        std::unique_ptr<BaseResult> result(new BaseResult);
        result->m_x = "Base Calced";

        return result;
    }

};

class DerivedCalc : public BaseCalc
{
public:

    virtual ~DerivedCalc() {}

    virtual std::unique_ptr<BaseResult> Calc() const
    {
        // I need to rely on the base calculations to get the fields relevant to the base
        std::unique_ptr<BaseResult> baseResult = BaseCalc::Calc();

        // However, I want to perform my addtional calculation relevant to derived, here.
        std::unique_ptr<DerivedResult> result(new DerivedResult(std::move(*baseResult)));
        result->m_y = 2;

        /* Results in error
        return result;
        */
        return std::move(result); // Is this how we do it?
    }
};

//--------------------------------------------------------------------------------------------------
int main()
{
    DerivedCalc calculator;
    std::unique_ptr<BaseResult> temp = calculator.Calc();

    // Cast - Got this part from https://stackoverflow.com/questions/21174593/
    std::unique_ptr<DerivedResult> actualResult;

    if (DerivedResult * cast = dynamic_cast<DerivedResult *>(temp.get()))
    {
        actualResult = std::unique_ptr<DerivedResult>(cast, std::move(temp.get_deleter()));
        temp.release();
    }
    else
    {
        std::exception("Failed to cast to DerivedResult");
    }

    std::string x = actualResult->m_x;
    int y = actualResult->m_y;

    return 0;
}

【问题讨论】:

  • @AnonMail 你能详细说明一下吗?您的意思是缺少的virtual 析构函数吗?
  • @anon 好的,你能描述得更详细些吗?您的意思是,这不是您一般继承的方式,还是您对基址的移动构造函数的关注?你会改变什么?
  • 有趣的是,这不是在 vs2017 下构建的。您设置actualResult 的行抱怨参数与unique_ptr 的任何构造函数都不匹配。
  • @Rook 我使用 2010 年构建的。不幸的是,我不得不在这个项目中使用它。我确实想知道为什么 2017 年会抱怨。我从另一个堆栈溢出问题中得到了那个演员部分,所以如果它不再有效,就必须更新它。然后,我们将了解如何将基本唯一 ptr 分配给派生的唯一 ptr 的额外复杂性
  • @Slava 这样的dynamic_pointer_cast 会返回什么?另一个unique_ptr 指向同一个对象?你好,双重毁灭。原始指针?那么和dynamic_cast&lt;AnotherType*&gt;(myPtr.get())没有什么区别@

标签: c++ c++11


【解决方案1】:

回答您的第一个问题,“我们如何返回指向派生类类型的基类类型的唯一指针?” (注意 std::make_unique 需要 c++14):

class DerivedCalc : public BaseCalc
{
public:

    virtual ~DerivedCalc() {}

    virtual std::unique_ptr<BaseResult> Calc() const
    {
        // I need to rely on the base calculations to get the fields relevant to the base
        std::unique_ptr<BaseResult> baseResult = BaseCalc::Calc();

        // However, I want to perform my addtional calculation relevant to derived, here.
        std::unique_ptr<BaseResult> result(std::make_unique<DerivedResult>(std::move(*baseResult)));
        DerivedResult& derived = static_cast<DerivedResult&>(*result);
        derived.m_y = 2;

        return result;
    }
};

对于您的第二个问题,“我是否使用移动构造函数正确地从基类创建派生类?”,您的版本有效,但您也可以移动派生数据字段以获得最佳性能:

class DerivedResult : public BaseResult
{
    ...
    DerivedResult(DerivedResult && rhs)
        :
        BaseResult(std::move(rhs))
        , m_y(std::move(rhs.m_y))
    {}
    ...
};

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-04-03
    • 1970-01-01
    • 2015-05-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多