I have unsuccessfully been trying to create a copy constructor of a class that instantiates a derived class.
Let's say I have the following pure virtual class:
class AbstractBar{
public:
virtual void printMe() = 0;
};
Class Bar
inherits from AbstractBar
as follows:
class Bar: public AbstractBar {
std::string name_;
public:
explicit Bar(std::string name) : name_ {std::move(name)}{};
void printMe() override { std::cout << name_ << std::endl; }
};
My class Foo
now attempts to make use of polymorphism by declaring a pointer to type AbstractClass
as follows:
class Foo{
std::unique_ptr<AbstractBar> theBar_;
public:
explicit Foo(std::unique_ptr<Bar> bar){
theBar_ = std::move(bar);
};
void printBar(){
theBar_->printMe();
}
};
I do however want Foo
to be copied so I add the following copy constructor:
Foo(const Foo &other) {
theBar_ = std::unique_ptr<AbstractBar>();
*theBar_ = *(other.theBar_);
}
And this is where it breaks.
What I gather is that this may be a problem since theBar
in the copy constructor thinks it is pointing to an AbstractBar
but when I try to copy the object it points to, in the next line, I actually give it a derived Bar
class.
Is there a proper way to implement this copy constructor?
CodePudding user response:
First off, std::unique_ptr<T>
is indeed unique. Therefore you cannot expect two things to point to the same instance-of-whatever by copying them. That said, I think what you're trying to do is clone whatever the "thing" is that is held by that member unique_ptr to allow a deep copy of a Foo
.
If that is the case, you need a covariant clone. See below:
#include <iostream>
#include <string>
#include <memory>
struct AbstractBar
{
virtual ~AbstractBar() = default;
virtual std::unique_ptr<AbstractBar> clone() = 0;
virtual void printMe() = 0;
};
class Bar : public AbstractBar
{
std::string name_;
public:
explicit Bar(std::string name) : name_{std::move(name)} {};
std::unique_ptr<AbstractBar> clone() override
{
return std::make_unique<Bar>(name_);
}
void printMe() override
{
std::cout << name_ << std::endl;
}
};
class Foo
{
std::unique_ptr<AbstractBar> theBar_;
public:
explicit Foo(std::unique_ptr<Bar> bar)
: theBar_(std::move(bar))
{
}
Foo(const Foo &other)
: theBar_(other.theBar_->clone())
{
}
void printBar()
{
theBar_->printMe();
}
};
int main()
{
Foo foo(std::make_unique<Bar>("Some String"));
Foo bar(foo);
foo.printBar();
bar.printBar();
}
Important: foo
and bar
will each have their own Bar
instance via a unique pointer to the abstract base of Bar
, namely AbstractBar
. Hopefully that was the intent. This isn't the only way to do this, but it is probably the easiest to understand.