Конструктор копирования для класса с уникальным ptr базового класса

Когда у класса есть unique_ptr базового класса, это хороший способ реализовать конструктор копирования.

Попробую объяснить на примере:

struct Base
{
    virtual void doSth() = 0; // to make the class abstract.
};

struct Derived : public Base
{
    virtual void doSth() override {}
};

struct Foo
{
    std::unique_ptr<Base> bar;

    Foo(const Foo& other) : bar(new Base(*other.bar))   // cant do it, its abstract.
    {
        bar = std::move(other.bar); // cant do it, reference object is modified.
    }
};

Здесь, поскольку класс является абстрактным, я не могу использовать его конструктор копирования. а также не может использовать перемещение по постоянной ссылке (на самом деле мы не должны этого делать, не изменяйте объект).

В итоге я получаю так:

struct Base
{
    virtual void doSth() = 0; // to make the class abstract.
};

struct Derived : public Base
{
    virtual void doSth() override {}

    Derived(const Base* b)
    {

    }
};

struct Foo
{
    std::unique_ptr<Base> bar;

    Foo(const Foo& other) : bar(new Derived(other.bar.get()))
    {

    }
};

Однако это кажется не совсем правильным, не так ли?


person bahti    schedule 18.05.2014    source источник
comment
@ 40two На самом деле, я видел вопрос, на который вы ссылались ранее. Но, возможно, я не мог ясно выразиться. Я беспокоюсь об unique_ptrs абстрактных базовых классов и о том, как обращаться с ними в конструкторах копирования.   -  person bahti    schedule 18.05.2014
comment
Спасибо за замечание, вы правы, я удаляю свой комментарий.   -  person 101010    schedule 18.05.2014
comment
Взгляните на этот вопрос о том, как глубоко скопировать объект, используя только указатель базового класса.   -  person merlin2011    schedule 18.05.2014
comment
Если вы хотите скопировать указанный объект, стандартный способ — через виртуальный метод clone().   -  person n. 1.8e9-where's-my-share m.    schedule 18.05.2014


Ответы (2)


Если вам нужно копировать полиморфно, вам нужно будет предоставить это в интерфейсе типа, который вы держите. Добавьте виртуальную функцию clone к Base и используйте ее для создания копии, которую можно сохранить в скопированном Foo.

Другие варианты включают отказ от копирования (удаление конструктора копирования) или использование семантики ссылок (копии относятся к одному и тому же объекту: замените unique_ptr на shared_ptr), но ни один из этих вариантов не предоставляет копий.

person David Rodríguez - dribeas    schedule 18.05.2014

Вот код ответа Дэвида. Обратите внимание, что виртуальный clone() описан в этом ответе.

#include <stdlib.h>
#include <cstddef>
#include <memory>


struct Base
{
   virtual void doSth() = 0; // to make the class abstract.
   virtual Base* clone() const = 0;
};

struct Derived : public Base
{
    virtual void doSth() override {}
    virtual Derived* clone() const {
        return new Derived(*this);
    }
};

struct Foo
{
    std::unique_ptr<Base> bar;

    Foo(const Foo& other) : bar(other.bar->clone())   // cant do it, its abstract.
    {

    }
};
person merlin2011    schedule 18.05.2014
comment
Спасибо за измененный код. - person bahti; 18.05.2014