Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
160 views
in Technique[技术] by (71.8m points)

c++ - Clone derived class from base class pointer

In our legacy project we have a function that takes reference to a base class and creates a copy of the derived class on the heap. This is solved essentially like this: https://godbolt.org/z/9ooM4x

#include <iostream>

class Base
{
public:
    virtual Base* vclone() const = 0;
    int a{7};
};

class Derived : public Base
{
public:
    Derived() 
    {
        a = 8; 
    }

    Base* vclone() const override
    {
        return new Derived(*this);
    }
};

Base* clone(const Base& original)
{
    return original.vclone();
}

int main()
{
    Derived d1;;
    auto* d2 = clone(d1);

    std::cout << d2->a << std::endl;
}

This works, but I would like to get rid of the boilerplate vclone method that we have to have in every single derived class.

We have hundreds of derived classes, some of them derived not directly from Base, but from some of the other derived classes too. So if we forget to override the vclone method, we may not even get a warning of the slicing that will happen.

Now, there is much to say about such a design, but this is 10-15 year old code that I try to modernize step by step. What I do look for, is a templatized version of clone that does not depend on a virtual method. What I want, is a clone function like this:

Base* clone(const Base& original)
{
    return new <Actual Derived Type>(original);
}

The actual derived type is somewhat known, since a dynamic_cast will fail if trying to cast to it with wrong type, but I don't know if it is possible to access the actual type in a way that I want. Any help would be appreciated.

question from:https://stackoverflow.com/questions/65916601/clone-derived-class-from-base-class-pointer

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I also think you probably cannot improve the code in the sense to make it shorter. I would say this implementation is basically the way to go.

What you could do is to change the return value of Derived::clone to Derived *. Yes C++ allows this.

Then a direct use of Derived::clone yields the correct pointer type and Base::clone still works as expected

class Derived : public Base
{
public:
    Derived() 
    {
        a = 8; 
    }

    Derived* vclone() const override  // <<--- 'Derived' instead of 'Base'. 
    {
        return new Derived(*this);
    }
};

I would also rename to vclone member function to clone (There is no need to have two names).

The free function clone could be made a template so that it works for all classes and returns the right pointer type

template <class T>
T *clone(const T *cls)
{
  return cls->clone();
}

However, all these changes do not make the code shorter, just more usable and perhaps more readable.

To make it a little shorter you might use an CRTP approach.

template <class Derived, class Base>
class CloneHelper: public Base {
    Derived* vclone() const override  
    {
        return new Derived(* static_cast<Derived *>(this) );
    }
};
// then use
class Derived : public CloneHelper<Derived, Base>
{
public:
    Derived() 
    {
        a = 8; 
    }
};

However, I am not sure if it is worth it. One still must not forget the CloneHelper, it makes inheritance always public and you cannot delegate to the Base constructor so easily and it is less explicit.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...