简体   繁体   中英

Pass in unique pointer for inherited class to constructor with unique pointer for base class?

Is it possible to do the following: I have an inherited class B from base class A. I want to create a constructor for a method that takes in a unique pointer to class A but still accept unique pointers to class B, similar to pointer polymorphism.

void Validate(unique_ptr<A> obj) {obj->execute();}
...

unique_ptr<B> obj2;
Validate(obj2);

This doesn't seem to work as I've written it (I get a No matching constructor for initialization error), but I wonder if this is still possible?

Polymorphism works on std::unique_ptr objects, just as it does on raw pointers. So, if you create a std::unique_ptr<A> for (the address of) a B object, then you can pass that to your Validate function; then, assuming there are virtual functions in the classes, polymorphism will kick-in when you call the execute function on the passed smart pointer.

#include <iostream>
#include <memory>

class A {
public:
    virtual void execute() { std::cout << "From A...\n"; }
    virtual ~A() = default;
};

class B :public A {
public:
    void execute() override { std::cout << "From B...\n"; }
    ~B() override = default;
};

void Validate(std::unique_ptr<A>& obj) // MUST pass by reference!
{
    obj->execute();
}

int main()
{
    B obj2;
    std::unique_ptr<A> p2{ &obj2 };
    Validate(p2);
    return 0;
}

Important Note: Your code attempts to pass a std::unique_ptr by value ; this is not allowed, as a copy will be made and then that copy will (eventually) be destroyed, and those operations aren't allowed on std::unique_ptr ; thus, in my code, I have changed that argument to be passed by reference .

Your issue doesn't really have anything to do with polymorphism, but rather in how unique_ptr<> works in general.

If Validate() is not meant to take ownership of obj , then it should not accept a unique_ptr<> in the first place. It should accept either a raw pointer or a reference depending on whether nullptr is an expected valid value:

void Validate(A* obj) {
  if(obj) {
    obj->execute();
  }
}

...

unique_ptr<B> obj2;
Validate(obj2.get());

// Or

void Validate(A& obj) {obj.execute();}

...

unique_ptr<B> obj2;
Validate(*obj2);

On the other hand, if Validate() is meant to take ownership of the passed object, then you need to move the pointer, as it cannot be copied, which will null-out the original pointer. That's the whole point of unique_ptr<> after all. There can only be one of them pointing at a given object.

void Validate(unique_ptr<A> obj) {obj->execute();}

...

unique_ptr<B> obj2;
Validate(std::move(obj2));

// Obj2 is now null.

You cannot copy a unique pointer.

If you wish to transfer the ownership to the Validate function, then you must move from the unique pointer:

Validate(std::move(obj2));

If ~A isn't virtual, then you may not use std::unique_ptr<A> because it would try to destroy the object through a pointer to the base which would result in undefined behaviour. You could use a custom deleter in such case.


If you don't wish to transfer ownership, then don't use a unique pointer parametr in the first place. Use a reference instead:

void Validate(A& obj) {
    obj.execute();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM