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

У меня есть абстрактный класс сказать Figure и некоторые производные классы: Circle, Square...

Фигура класса реализует:

private:
  virtual double varea()=0;
  double multiplier;
public:
  virtual Figure * clone()=0;
  double area() { return varea()*multiplier; }

Фигуры, например Площадь, ведут себя так:

private:
  double L;
public:
  virtual Figure * clone() {return new Square(*this);}
  virtual double varea() {return L*L;}

У меня возникают трудности с назначением множителя переменной при вызове метода clone. Каков наилучший способ достичь этого? Конечно, это просто глупый пример с рядом обходных путей, но в действительности, с несколькими уровнями деривации, они не так очевидны, поэтому, пожалуйста, придерживайтесь этого паттерна.


Должен ли я пойти на виртуальный интерфейс также для метода клона? Таким образом, я могу назначить множитель непосредственно в классе Figure без необходимости сообщать каждой фигуре свой множитель.

3 ответа

Решение

Если вы не объявите конструктор копирования для вашего класса Figure, язык предоставит вам один бесплатный, и он будет общедоступным. Вам не нужен этот бесплатный конструктор публичных копий. Это приведет к нарезке. Создайте свой конструктор копирования для защищенного класса Figure. Ваш конструктор копии для неабстрактных производных классов должен вызывать этот конструктор защищенной копии. При этом функция-член клона так же проста, как new DerivedClass (*this):

class Figure {
private:
   virtual double varea()=0;
   double multiplier;
protected:
   Figure () : multiplier(1.0) {}
   Figure (const Figure& src) : multiplier(src.multiplier) {}
public:
   virtual Figure* clone()=0;
   double area() { return varea()*multiplier; }
};

class Square: public Figure {
private:
   virtual double varea() {return L*L;}
   double L;
public:
  Square(const Square & src) : Figure(src), L(src.L) {}
  virtual Figure* clone() {return new Square(*this);}
};

Обратите внимание:

  • я сделал Square::varea() частный, потому что так заявлено в классе Figure, Представление частного метода родительского класса как общедоступного в производном классе, как правило, немного сомнительно.
  • Есть проблема с оператором присваивания. Я оставлю это на ваше усмотрение.
  • Вам нужен какой-то способ установить multiplier,

Наследование неловко связывается с семантикой копирования. Тем не менее, одно решение может позволить конструктору копирования выполнить эту работу:

struct Base
{
public:
    Base()=default;
    virtual ~Base()=default;

    virtual Base* clone()=0;

    Base& operator=(Base const &) = delete;
    Base(Base&&)=delete;
protected:
    Base(Base const&) = default;
};

struct Derivated : Base
{
public:
    Derivated()=default;

    virtual Derivated * clone()
    {
        return new Derivated (*this);
    }
protected:
    Derivated(Derivated const&) = default;
};

Добавьте защищенные средства доступа к классу фигур:

protected:
  double getMultiplier() { return multiplier; }
  void setMultiplier(double newValue) { multiplier = newValue; }

чем вы будете иметь доступ к множителю, хотя у вас не будет прямого доступа к члену..

Другие вопросы по тегам