Home > Back-end >  Copying an object with a polymorphic member in C
Copying an object with a polymorphic member in C

Time:02-12

I wish to express that each object of type V owns an object of type B. B is a polymorphic type, and is therefor accessed through a pointer or reference to prevent slicing (C.145). I find it natural to express this as following

    class B {};
    
    class V {
    public:
        unique_ptr<B> p;
    };

I can now derive B and assign the derived to p, as such

    class D : public B {};
    
    V x;
    x.p = make_unique<D>();

Because B is a polymorphic type, it is advised to suppress copies and moves to prevent slicing (C.67).

    B(const B&) = delete;
    // etc...

It is impossible to copy p, because it's a unique_ptr, and I have now prevented deep copying as well, unless a clone function is implemented (C.130). Is the implementation of a virtual clone function an indication of poor design? It seems like a work-around.

By following these two rules from the C Core Guidelines, I have prevented the copying of V. If V is a vertex in a graph, and graphs must be copied, then I have created a problem for myself; No graphs can be copied anymore. Implementing a custom copy assignment for V doesn't solve that issue, because deep-copying of p is impossible.

After searching around the web, I found no solution which felt natural, and I concluded that there must be something very wrong with my way of thinking. Is it a bad idea to have a polymorphic member? If one should not copy a polymorphic object then one can neither copy any object owning another polymorphic object.

The member can be a shared_ptr instead, but then the semantics become wrong, because this is not a shared object. I lack a way of expressing something that is so obviously simple to conceptualize. How do I copy an object that owns another polymorphic object while not sacrificing semantics? Every post I've read where someone poses a question regarding copying of unique_ptr, deep copying etc..., are usually met with an answer that entails a sacrifice, most likely because the way of solving the problem is wrong in the first place. I have a feeling there is a very simple and elegant solution to this.

CodePudding user response:

You need to ask yourself a question : Why should B not be copyable?

The example you described, with a graph owning one (or probably multiple) vertexes shows the opposite : B should be copyable! What you don't want is two graphs sharing the same vertex instance.

So you can create a copy constructor / clone method for V along those lines :

V::V(const V& other)
{
  p = other.p->clone();
}

std::unique_ptr<B> D::clone()
{
  return std::make_unique<D>(...);
}

Have a look at this article for a better explanation.

  • Related