Чистый виртуальный метод возвращает тип класса, используя конструктор копирования в С++

Я делаю что-то под названием «глубокая копия», метод clone() требует возврата нового экземпляра типа производного класса с использованием его конструктора копирования.

Устройство.ч

class Device : public Object{
public:
    Device();
    Device(const Device& copy);
    ~Device();
    virtual Device* clone() = 0;
};

Радар.ч

class Radar : public Device {
public:
    Radar();
    ~Radar();
    Radar(const Radar &Copy);
    Device* clone();
};

Радар.cpp

Radar::Radar() {
}

Radar::Radar(const Radar& copy) {
}

Radar::~Radar() {
}

Device* Radar::clone() {
}

Я понятия не имею, как справиться с этим методом с помощью конструктора копирования, кто-нибудь может мне помочь?


person Joey Zhang    schedule 30.10.2015    source источник
comment
Вам нечего клонировать. У вашего класса действительно есть некоторые переменные-члены?   -  person NathanOliver    schedule 30.10.2015
comment
да. В нем есть несколько членов. Я удалил их для удобства чтения   -  person Joey Zhang    schedule 30.10.2015


Ответы (2)


Примечание. Вы можете рассмотреть возможность использования Radar* clone() override; в производном классе, что позволит экземпляру производного типа клонировать себя и поддерживать тот же тип (это называется ковариантным возвращаемым типом).

вернуть новый экземпляр типа производного класса, используя его конструктор копирования

return new Radar(*this);
  • new потому что вам нужен указатель на новый экземпляр класса
  • *this, потому что сигнатура конструктора копирования Radar(const Radar&)
person James Adkison    schedule 30.10.2015
comment
Вы можете использовать CRTP, чтобы избежать реализации этого для каждого производного класса. - person Brandlingo; 30.10.2015
comment
Это действительно полезно. Спасибо большое. - person Joey Zhang; 30.10.2015
comment
@JoeyZhang Если вы хотите избежать скуки ( т.е. бремя обслуживания) они упоминают. - person James Adkison; 30.10.2015

Класс с виртуальными функциями обычно не имеет конструктора копирования, потому что копировать объекты таких классов обычно не имеет смысла. Разрешение конструктора копирования открывает двери для всевозможных опасных ошибок, связанных с нарезкой.

Другими словами (выделено мной):

Я делаю что-то под названием "глубокое копирование", метод clone() требует вернуть новый экземпляр типа производного класса, используя его конструктор копирования

Нет, он абсолютно не требует конструктора копирования. Это должно предотвратить копирование, удалив конструктор копирования и оператор присваивания копии.

Вот пример того, как это должно быть сделано. Обратите внимание, что я сделал деструктор виртуальным и добавил несколько примеров членов. Я также изменил подпись clone на const и использовал override для включения дополнительных проверок компиляции.

class Device : public Object {
public:
    Device() {}
    Device(const Device&) = delete;
    Device& operator=(const Device&) = delete;
    virtual ~Device() {}
    virtual Device* clone() const = 0;
};

class Radar : public Device {
public:
    Radar(int i, const std::string& s) : i(i), s(s) {}
    Radar* clone() const override 
    {
        return new Radar(i, s);
    }
private:
    int i;
    std::string s;
};

В зависимости от того, что требуется вашему дизайну, конструктор Radar, вызываемый clone, также может быть private.

Другое дело, что вы можете рассмотреть дизайн на основе std::unique_ptr:

class Device : public Object {
public:
    Device() {}
    Device(const Device&) = delete;
    Device& operator=(const Device&) = delete;
    virtual ~Device() {}
    virtual std::unique_ptr<Device> clone() const = 0;
};

class Radar : public Device {
public:
    Radar(int i, const std::string& s) : i(i), s(s) {}
    std::unique_ptr<Device> clone() const override 
    {
        return std::make_unique<Radar>(i, s);
    }
private:
    int i;
    std::string s;
};
person Christian Hackl    schedule 30.10.2015
comment
Просто для ясности: ваше утверждение об удалении конструктора копирования относится только к базовому классу, а не к производному классу, верно? Если вы также говорите о производном классе, то почему Radar r(0, ""); ... r = other; (где other тип Radar) должен быть запрещен? - person James Adkison; 30.10.2015
comment
К вашему сведению, я просто пытаюсь убедиться, что понимаю ваш совет и его обоснование. - person James Adkison; 30.10.2015
comment
@JamesAdkison: запрет конструктора копирования и оператора присваивания копии в базовом классе автоматически запрещает обе функции для всех производных классов. - person Christian Hackl; 30.10.2015