Is it possible to clone a polymorphic object without manually adding overridden clone method into each derived class in C++?

后端 未结 6 2104
迷失自我
迷失自我 2020-12-30 01:21

The typical pattern when you want to copy a polymorphic class is adding a virtual clone method and implement it in each derived class like this:

Base* Derive         


        
6条回答
  •  不思量自难忘°
    2020-12-30 01:41

    If you can control how you pass around the polymorphic type, use type erasure. In particular, the proposed std::polymorphic_value calls the derived copy constructor when it is copied. You can imagine it as something like this:

    template 
    class polymorphic_value {
    public:
        template >::value, int> = 0>
        explicit polymorphic_value(D&& value)
            : ptr{std::make_unique>>(std::forward(value))}
        {}
    
        polymorphic_value(polymorphic_value const& rhs)
            : ptr{rhs.ptr->clone()}
        {}
    
        B const& get() const { return ptr->get(); }
    
        B& get() {
            // Safe usage of const_cast, since the actual object is not const:
            return const_cast(ptr->get());
        }
    
    private:
        struct base_t {
            virtual ~base_t() = default;
            virtual std::unique_ptr clone() const = 0;
            // With more effort, this doesn't have to be a virtual function.
            // For example, rolling our own vtables would make that possible.
            virtual B const& get() const = 0;
        };
    
        template 
        struct derived_t final : public base_t {
            explicit derived_t(D const& d)
                : value{d}
            {}
    
            explicit derived_t(D&& d)
                : value{std::move(d)}
            {}
    
            std::unique_ptr clone() const override {
                return std::make_unique(value);
            }
    
            B const& get() const override {
                return value;
            }
    
            D value;
        };
    
        std::unique_ptr ptr;
    };
    

    For a thorough implementation which follows the proposal, see jbcoe's github repository.

    Sample usage:

    class Base {
    public:
        virtual ~Base() = default;
    };
    
    class Derived : public Base {
    public:
        Derived() = default;
        Derived(Derived const&);
    };
    
    int main() {
        polymorphic_value it{Derived{}};
        auto const copy = it;
    }
    

    Live on Godbolt

提交回复
热议问题