将导出的 std::unique_ptr 转换为基类并将所有权作为参数传递

Sav*_*owW 2 c++ inheritance smart-pointers unique-ptr

我有这个代码:

#include <iostream>
#include <memory>

class Base
{
public:
    virtual void doSmth() = 0;
};

class Der1 : Base
{
public:
    void doSmth() final
    {
        std::cout << "Hello from der1\n";
    }
};

class Der2 : Base
{
public:
    void doSmth() final
    {
        std::cout << "Hello from der2\n";
    }
};

class Owner
{
public:
    Owner(std::unique_ptr<Base> passedptr)
    {
        ptr = std::move(passedptr);
    }

    std::unique_ptr<Base> ptr;
};

int main()
{
    auto der = std::make_unique<Der1>();
    Owner owner(std::move(der)); // Fails, need to convert
    owner.ptr->doSmth();
}
Run Code Online (Sandbox Code Playgroud)

我希望该类Owner在构造函数中采用基指针并将其unique_ptr成员设置为它。我知道我需要用 来传递它std::move(),但我不明白如何将它转换为基类。

我已经看到派生类的 unique_ptr 作为将 unique_ptr 传递给基类的函数的参数,但它的解决方案似乎不起作用,我不能像我一样将指针移动到派生类它在我的代码中,我无法创建这样的基指针:

std::unique_ptr<Base> der(new Der1());
Run Code Online (Sandbox Code Playgroud)

如何正确转换和传递所有权?

JeJ*_*eJo 5

如何正确转换和传递所有权?

您需要执行几个步骤才能使代码正确。

  1. 派生类应该继承Base,public盟友,以便所有编译器生成的构造函数Base(即移动构造函数和移动赋值)也对它们有用。

  2. Base类缺少虚拟析构函数,并且您正在分配子指针(即在Owner类中),因此将通过Base类指针删除(即std::unique_ptr<Base> ptr;)。这将导致未定义的行为。

    阅读此处更多内容:何时使用虚拟析构函数?

  3. 在 中Owner,您应该更好地使用构造函数初始值设定项 list,而不是单独构造Owner并分配成员。

  4. (可选),您可能希望为 提供一个模板构造函数Owner,以便可以同时传递Der1Der2

代码如下所示:请参阅 godbolt.org 中的现场演示


class Base
{
public:
    virtual void doSmth() = 0;
    virtual ~Base() = default; // add this for designed behavior!
};

class Der1 : public Base
//           ^~~~~~~ ---> Inherit public ally
{
public:
    // ....
};

class Der2 : public Base
//           ^~~~~~~ ---> Inherit public ally
{
public:
    // ....
};

class Owner
{
public:
    template<typename Derived> // --> Templated
    Owner(std::unique_ptr<Derived>&& passedptr)
        : ptr(std::move(passedptr))
    {}

    std::unique_ptr<Base> ptr;
};
Run Code Online (Sandbox Code Playgroud)