C++: Deep Copying a Base Class Pointer

C++: Deep copying a Base class pointer

You need to use the virtual copy pattern: provide a virtual function in the interface that does the copy and then implement it across the hierarchy:

struct base {
virtual ~base() {} // Remember to provide a virtual destructor
virtual base* clone() const = 0;
};
struct derived : base {
virtual derived* clone() const {
return new derived(*this);
}
};

Then the DeepCopy object just needs to call that function:

class DeepCopy 
{
Base * basePtr;
public:
DeepCopy(DeepCopy const & dc) // This should be `const`
: basePtr( dc.basePtr->clone() )
{}
};

Deep copy of std::vector of pointers to a base class

The easiest way is to implement some form of cloning, then using std::transform:

#include <algorithm>
#include <iostream>
#include <iterator>
#include <memory>
#include <vector>

struct base {
// For constructors and destructors, it's business as usual.
// Remember to implement the rule of five.
base() {std::cout << "new base\n";}
base(const base& o) {
std::cout << "copied base\n";
}
virtual ~base() {std::cout << "destructed base\n";}
// This is the virtual copy function. We need this because only
// the actual derived class will know how to copy itself. The
// only way to forward this knowledge to a pointer to the base
// class is via a virtual function.
// You can make this pure virtual, if you don't mind
// the base being abstract (or if you *want* to make it
// abstract). It'll be safer this way.
virtual base* copy() {return new base(*this);}
};

struct derived : base {
derived() : base() {std::cout << "new derived";}
derived(const derived& o) : base(o) {
std::cout << "copied derived\n";
}
virtual ~derived() {std::cout << "destructed derived\n";}
base* copy() override {return new derived(*this);}
};

// example of deep copying
int main() {
std::vector<std::unique_ptr<base>> v;
v.emplace_back(new base());
v.emplace_back(new derived());
std::vector<std::unique_ptr<base>> copy_of_v;

// The transformation merely calls copy(). Each object will be copied into
// an instance of the correct type.
std::transform(v.begin(), v.end(), std::back_inserter(copy_of_v), [](auto& item){
return std::unique_ptr<base>(item->copy());
});
}

Copying derived entities using only base class pointers, (without exhaustive testing!) - C++

This approach is the preferred way of copying polymorphic objects because it offloads the responsibility of determining how to copy an object of an arbitrary type to that object, rather than trying to determine it at compile-time. More generally, if you don't know what the base class pointer points at at compile-time, you can't possibly know which of the many potential pieces of code you would need to execute in order to get a correct copy. Because of this, any working solution will need a dynamic selection of code, and the virtual function is a good way to do this.

Two comments on your actual code. First, C++ inheritance allows a derived class overriding a base class member function to have the derived function return a pointer of a type more specific than the base class version. This is called covariance. As an example, if a base class function is

virtual Base* clone() const;

Then a derived class can override it as

virtual Derived* clone() const;

And this will work perfectly fine. This allows you, for example, to have code like this:

Derived* d = // something...
Derived* copy = d->clone();

Which, without the covariant overload, wouldn't be legal.

Another detail - in the code you have, you explicitly static_cast the derived pointers to base pointers in your code. This is perfectly legal, but it's not necessary. C++ will implicitly convert derived class pointers to base class pointers without a cast. If, however, you use the covariant return type idea, this won't come up because the return type will match the type of the objects you'll be creating.

Deep copying a vector of pointers in derived class

Thank you Marius Bancila, you are right, the problem was that I was just copying the pointers, and not creating new objects in the new vector. I called clone() on each object, and now it works perfectly! Here is the working clone function, in case anyone stumbles upon this thread in the future:

    CipherQueue* clone() const
{
CipherQueue* to_clone = new CipherQueue;
to_clone->tarolo = this->tarolo; //First we copy the pointers
for (size_t i = 0; i < this->tarolo.size(); i++)
{
to_clone->tarolo[i] = tarolo[i]->clone(); //Then we use the clone function on each element to actually create new objects, and not just have copied pointers
}
return to_clone;
}

In the end, it seems like I didn't need the copy constructor at all. You can make the clone function without it.

How do you solve the deep copy of an abstract class problem when you are working with an abstract class from a library?

For the sake of this answer, let's assume you are working with the SFML's sf::Shape abstract class:

sf::Shape hierarchy

So, you are probably dealing with sf::CircleShape, sf::ConvexShape, and sf::RectangleShape objects through sf::Shape pointers or references. These are concrete classes.

Instead of working through sf::Shape you could define the following abstract class ClonableShape:

struct ClonableShape {
virtual ~ClonableShape() = default;

virtual std::unique_ptr<ClonableShape> clone() const = 0;

// extend at will with the member functions from sf::Shape, e.g.:
virtual const sf::Vector2f& getPosition() const = 0;
// ...
};

You can use this interface to clone those objects polymorphically by insantiating the following class template with the concrete classes above:

template<typename T>
struct Clonable: T, ClonableShape {
Clonable() = default;

template<typename... Args>
Clonable(Args... args): T(args...) {}

std::unique_ptr<ClonableShape> clone() const override {
return std::make_unique<Clonable<T>>(*this);
}

const sf::Vector2f& getPosition() const override {
// careful not to call ClonableShape::getPosition() instead
return T::getPosition();
}
};

That is, this solution relies on the inheritance but you may want to consider composition insteadX.

Finally, you can clone the shape objects polymorphically:

std::unique_ptr<ClonableShape> shapeA(new Clonable<sf::RectangleShape>(sf::Vector2f{4, 4}));
std::unique_ptr<ClonableShape> shapeB = std::make_unique<Clonable<sf::CircleShape>>(4.f);

std::unique_ptr<ClonableShape> shapeC = shapeA->clone();
auto shapeD = shapeB->clone();

Since sf::Shape publicly derives from sf::Drawable and there are several functions in the SFML library that accept a reference to sf::Drawable, e.g., sf::RenderWindow::draw(), you may want to extend the ClonableShape interface above to being able to implicitly convert to sf::Drawable& by adding:

virtual operator sf::Drawable&() = 0;

and then overriding it in Clonable<> as:

operator sf::Drawable&() override { return *this; }

This way, if you have a function like:

void draw(sf::Drawable&);

You will be able to call it by just writing:

draw(*shapeA);

X If don't rely much on the concrete classes – e.g., if you don't work directly with Clonable<sf::RectangleShape> or Clonable<sf::CircleShape> – then you may want to switch from inheritance to composition as you won't be depending much on the member functions inherited by having the concrete shapes as public bases but rather on those you specify in ClonableShape:

template<typename T>
class Clonable: public ClonableShape {
T shape_; // as data member instead of public base
public:
Clonable() = default;

template<typename... Args>
Clonable(Args... args): shape_(args...) {}

std::unique_ptr<ClonableShape> clone() const override {
return std::make_unique<Clonable<T>>(*this);
}

const sf::Vector2f& getPosition() const override {
// careful not to call ClonableShape::getPosition() instead
return shape_.getPosition();
}

// operator sf::Drawable&() override { return shape_; }
};

How do you deep copy a vector of derived class pointers via the copy constructor?

To do this correctly two more things need to be added to the base class:

class item {
public:

virtual ~item() {}

The base class must have a virtual destructor.

    virtual item *clone() const=0;

And an abstract method that's traditionally called clone(). Every one of your subclasses must implement clone(), typically by using a copy constructor:

class Cat : public item {
public:

item *clone() const override { return new Cat{*this}; };

The same thing is done for all other subclasses of item. Then, with this in place you can clone a vector of these objects, correctly:

    for (int i = 0; i < inventory.size(); ++i) {
inventory[i] = orig.inventory[i]->clone();
}

Deep Copy of an Object that contains a Pointer to Pointers

I don't have time to check your complete code.

But the root = new vertex(*p_BTree.root); in your copy constructor would be a problem if root is nullptr.

And your vertex manages resources (it has a delete in the destructor), but does not follow the rule of three/five.

So as soon as a copy of an instance of vertex is created, the pointers will be copied, and two instances of vertex manage the same pointers which results in double free.

And using this in a node of a tree is problematic:

 ~vertex(){
delete leftChild;
delete rightChild;
leftChild = nullptr;
rightChild = nullptr;
};

If you have a tree with a large depth you could encounter a stackoverflow. The reason for that is because the deletion is done recursively. You want to collect the nodes of the tree in the root and delete them there.

The same is true for the deep copying in the copy constructor and copy assignment operator you have to create for vertex.


Further notes:

  • doing root = nullptr; after the delete in the destructor is something you don't need to do. Same for vertex.
  • be consistent and don't mix NULL and nullptr. You should stick with nullptr.
  • root = NULL; in your constructor should be either done with a default value for the member variable or through the member initializer lists of the constructor. Same for vertex.


Related Topics



Leave a reply



Submit