lundi 24 avril 2017

Clone pattern for std::shared_ptr in C++

Why do you need (in order to make it compile) the intermediate CloneImplementation and std::static_pointer_cast (see Section 3 below) to use the Clone pattern for std::shared_ptr instead of something closer (see Section 2 below) to the use of raw pointers (see Section 1 below)? Because as far as I understand, std::shared_ptr has a generalized copy constructor and a generalized assignment operator?

1. Clone pattern with raw pointers:

#include <iostream>

struct Base {
    virtual Base *Clone() const {
        std::cout << "Base::Clone\n";
        return new Base(*this);
    }
};

struct Derived : public Base {
    virtual Derived *Clone() const override {
        std::cout << "Derived::Clone\n";
        return new Derived(*this);
    }
};

int main() {
  Base *b = new Derived;
  b->Clone();
}

2. Clone pattern with shared pointers (naive attempt):

#include <iostream>
#include <memory>

struct Base {
    virtual std::shared_ptr< Base > Clone() const {
        std::cout << "Base::Clone\n";
        return std::shared_ptr< Base >(new Base(*this));
    }
};
struct Derived : public Base {
    virtual std::shared_ptr< Derived > Clone() const override {
        std::cout << "Derived::Clone\n";
        return std::shared_ptr< Derived >(new Derived(*this));
    }
};

int main() {
  Base *b = new Derived;
  b->Clone();
}

Output:

error: invalid covariant return type for 'virtual std::shared_ptr<Derived> Derived::Clone() const'
error:   overriding 'virtual std::shared_ptr<Base> Base::Clone() const'

3. Clone pattern with shared pointers:

#include <iostream>
#include <memory>

struct Base {

    std::shared_ptr< Base > Clone() const {
        std::cout << "Base::Clone\n";
        return CloneImplementation();
    }

private:

    virtual std::shared_ptr< Base > CloneImplementation() const {
        std::cout << "Base::CloneImplementation\n";
        return std::shared_ptr< Base >(new Base(*this));
    }
};
struct Derived : public Base {

     std::shared_ptr< Derived > Clone() const {
        std::cout << "Derived::Clone\n";
        return std::static_pointer_cast< Derived >(CloneImplementation());
    }

private:

    virtual std::shared_ptr< Base > CloneImplementation() const override {
        std::cout << "Derived::CloneImplementation\n";
        return std::shared_ptr< Derived >(new Derived(*this));
    }
};

int main() {
  Base *b = new Derived;
  b->Clone();
}

Aucun commentaire:

Enregistrer un commentaire