I have this code:
#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();
}
I want the Owner
class to take a base pointer in constructor and set its unique_ptr
member to it. I understand that I need to pass it with std::move()
, but I don't understand how I can convert it to the base class.
I've seen unique_ptr to a derived class as an argument to a function that takes a unique_ptr to a base class, but solutions from it don't seem to work, I can't just move a pointer to a derived class like I do it in my code, and I can't create a base pointer like this:
std::unique_ptr<Base> der(new Der1());
How can I convert and pass ownership properly?
How can I convert and pass ownership properly?
There are a few steps you need to do, to make your code correct.
The derived classes should be inheriting the Base
, public
ally, so that all the compiler generated constructors of Base
(i.e. move constructor and move assignment) also be useful for them.
Base
class is missing a virtual destructor, and you are assigning the child pointers (i.e. in Owner
class), which will be therefore deleted through Base
class pointers (i.e. std::unique_ptr<Base> ptr;
). This will lead to undefined behavior.
Read here more: When to use virtual destructors?
In Owner
, you should be better using constructor initializer list, instead of constructing the Owner
and assigning the members separately.
(Optionally), you might probably want to provide a template constructor for Owner
, so that one can pass both Der1
and Der2
.
The code would look like: See live demo in 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;
};