C++ elegantly clone derived class by calling base class

后端 未结 3 661
滥情空心
滥情空心 2021-01-15 04:12

I have a need to clone a derived class given only a reference or pointer to the base class. The following code does the job, but doesn\'t seem elegant, because I\'m putting

相关标签:
3条回答
  • 2021-01-15 04:50

    You could always stick all the cloning logic into its own class in the middle of the hierarchy:

    template <class Derived, class Base>
    class CloneCRTP : public Base {
    public:
        Derived* clone() const override {
            return new Derived(static_cast<Derived const&>(*this));
        }
    };
    

    And then:

    class B : public CloneCRTP<B, A>
    {
        int i;
    public:
        virtual ~B() { cout << "destroyed b" << endl; }        
    };
    

    No more boilerplate.

    0 讨论(0)
  • 2021-01-15 04:51

    To achieve clone that works as with covariant return type, there is a need for some more complicated CRTP:

    class Shape {
        // virtual
        virtual Shape* do_clone() const = 0;
    public:
        virtual ~Shape() {}
        // non-virtual
        Shape* clone() const {
            return do_clone();
        }
        // ...
    };
    
    template <class Derived, class Base>
    class CloneCRTP : public Base {
        // virtual
        Shape* do_clone() const override {
            return new Derived(static_cast<Derived const&>(*this));
        }
    public:
        // non-virtual
        Derived* clone() const {
            return static_cast<Derived*>(do_clone());
        }    
    };
    

    Usage:

    class Rectangle: public CloneCRTP<Rectangle, Shape> { /*...*/ };    
    class Triangle: public CloneCRTP<Triangle, Shape> { /*...*/ };
    
    int main() {
        Rectangle* r1 = new Rectangle{};
    
        // getting the proper type from clone:
        Rectangle* rcopy = r1->clone();
    
        delete rcopy;
        delete r1;
    
        Triangle t1{};
    
        // getting the proper type from clone:
        Triangle* tcopy = t1.clone();
    
        delete tcopy;
    }
    

    Code: http://coliru.stacked-crooked.com/a/d8781deee5f7f6ea

    0 讨论(0)
  • 2021-01-15 05:03

    You can rely on the CRTP idiom.
    It follows a minimal, working example:

    struct B {
        ~virtual ~B() { }
        virtual B* clone() = 0;
    };
    
    template<class C>
    struct D: public B {
        B* clone() {
            return new C{*static_cast<C*>(this)};
        }
    };
    
    struct S: public D<S> { };
    
    int main() {
        B *b1 = new S;
        B *b2 = b1->clone();
        delete b1;
        delete b2;
    }
    
    0 讨论(0)
提交回复
热议问题