What's the best signature for clone() in C++?

后端 未结 8 1370
别那么骄傲
别那么骄傲 2020-12-05 10:41

As Scott Myers wrote, you can take advantage of a relaxation in C++\'s type-system to declare clone() to return a pointer to the actual type being declared:

         


        
相关标签:
8条回答
  • 2020-12-05 10:43

    Updating MSalters answer for C++14:

    #include <memory>
    
    class Base
    {
    public:
        std::unique_ptr<Base> clone() const
        {
            return do_clone();
        }
    private:
        virtual std::unique_ptr<Base> do_clone() const
        {
            return std::make_unique<Base>(*this);
        }
    };
    
    class Derived : public Base
    {
    private:
        virtual std::unique_ptr<Base> do_clone() const override
        {
            return std::make_unique<Derived>(*this);
        }
    }
    
    0 讨论(0)
  • 2020-12-05 10:50

    Tr1::shared_ptr<> can be casted like it were a raw pointer.

    I think have clone() return a shared_ptr<Base> pointer is a pretty clean solution. You can cast the pointer to shared_ptr<Derived> by means of tr1::static_pointer_cast<Derived> or tr1::dynamic_pointer_cast<Derived> in case it is not possible to determine the kind of cloned object at compile time.

    To ensure the kind of object is predictible you can use a polymorphic cast for shared_ptr like this one:

    template <typename R, typename T>
    inline std::tr1::shared_ptr<R> polymorphic_pointer_downcast(T &p)
    {
        assert( std::tr1::dynamic_pointer_cast<R>(p) );
        return std::tr1::static_pointer_cast<R>(p);
    }
    

    The overhead added by the assert will be thrown away in the release version.

    0 讨论(0)
  • 2020-12-05 10:56

    The syntax isn't quite as nice, but if you add this to your code above, doesn't it solve all your problems?

    template <typename T>
    std::auto_ptr<T> clone(T const* t)
    {
        return t->clone();
    }
    
    0 讨论(0)
  • 2020-12-05 10:58

    It depends on your use case. If you ever think you will need to call clone on a derived object whose dynamic type you know (remember, the whole point of clone is to allow copying without knowing the dynamic type), then you should probably return a dumb pointer and load that into a smart pointer in the calling code. If not, then you only need to return a smart_ptr and so you can feel free to return it in all overrides.

    0 讨论(0)
  • 2020-12-05 10:59

    You could have two methods, a virtual clone() that returns a smart pointer wrapper around the base type, and a non-virtual clone2() that returns the correct type of smart pointer.

    clone2 would obviously be implemented in terms of clone and encapsulate the cast.

    That way can get the most derived smart pointer that you know at compile time. It may not be the most derived type overall, but it uses all the information available to the compiler.

    Another option would be to create a template version of clone that accepts the type you are expecting, but that adds more burden on the caller.

    0 讨论(0)
  • 2020-12-05 11:03

    That's one reason to use boost::intrusive_ptr instead of shared_ptr or auto/unique_ptr. The raw pointer contains the reference count and can be used more seamlessly in situations like this.

    0 讨论(0)
提交回复
热议问题