Виртуальный оператор умножения в C ++ - PullRequest
0 голосов
/ 16 ноября 2011

У меня есть класс абстрактного предка, который называется Figure

class Figure {
public:
   string style, color, name;


   virtual void printInfo() = 0;
   /*
   different methods here
   */
   virtual Figure operator * (int prod) = 0;

};

И у меня есть класс Line (и несколько других), который наследует рисунок.

class Line : public Figure {
     /* .... */
     Line operator*(int prod);
};

Line Line::operator *(int prod) {
    Line temp = *this ;
    Point p = getPoint2();
    p.setXYZ(p.getX() * prod, p.getY() * prod, p.getZ() * prod);
    temp.setPoint2(p);
    return temp;
}

Дело в том, что я хочу иметь такого виртуального оператора, но если я напишу код, как указано выше, я получу десятки ошибок. Что я сделал не так?

Ответы [ 4 ]

2 голосов
/ 16 ноября 2011

Figure - абстрактный класс, поэтому вы не можете вернуть его по значению.Он абстрактный, потому что имеет чисто виртуальные методы.Абстрактные классы не могут быть созданы.

0 голосов
/ 16 ноября 2011

Чтобы добавить к предыдущим ответам: если вам действительно нужен оператор *, чтобы быть перегруженным, вы должны понять, что вам нужно найти какой-то способ создания нового Figure, который вы будете возвращать.

Однако прежде чем сделать это, лучше указать, что бинарный оператор * обычно должен быть перегружен вне класса, например:

T operator*(T const& lhs, T const& rhs);

Это может быть полезно сделатьэто друг, но это также часто не нужно.Если вы хотите, чтобы этот оператор вел себя по-разному, в зависимости от того, был ли передан T или производный от T, пусть он вызовет виртуальную T multiply(T const& rhs) const; функцию на одной из сторон (в любом случае, это хорошая идея).

Теперь, что касается возврата, есть несколько способов сделать это:

Сделать Figure не абстрактным и вернуть его по значению

Это довольно простое решение, но, к сожалению, оно мало что дает.Скорее всего, если вы используете полиморфизм, нарезка недопустима.

new Figure и возврат по ссылке

ШансЭто выглядит следующим образом:

T& operator*(T const& lhs, int rhs) {
    T* t = lhs.Clone(); // Clone returns a new derived-from-T.
    t->multiply(rhs);
    return *t;
}

Это работает, но затрудняет управление памятью: например, если выбрасывает multiply(), у вас есть утечка памяти.В общем, хотя это можно сделать, это не кажется разумным.

Используйте PImpl и возвращайте обертку по значению

Если честно, у меня нет практического опытас PImpl, но я думаю, что это (или что-то подобное) может быть применено здесь.Вместо прохождения Figure* s вы можете переименовать текущий Figure в FigureImpl и создать новый класс Figure, который будет иметь вид:

class Figure {
    // We don't want direct instantiation.
    Figure();
    Figure(FigureImpl* fi) : p_(fi) {}

  public:
    Figure(Figure const& f)
        : p_(f.p_->Clone())
    {}
    void PrintInfo(); // Hm, why not overload operator<<?
    Figure Multiply(int rhs) const {
      Figure f(p_.Clone());
      f.p_->Multiply(rhs);
      return f;
      // Or even:  return Figure(p_->Multiply(rhs.p_));
      // with Multiply returning a new FigureImpl*.
    }

  private:
    unique_ptr<FigureImpl*> p_;
};

Figure operator*(Figure const& lhs, int rhs) {
    return lhs.Multiply(rhs);
}

После этого вы можете иметь FigureImpl class и LineImpl class:

struct FigureImpl {
    virtual void printInfo() = 0;
    virtual void Multiply(int) = 0; // or make it const and return a FigureImpl*
};

struct LineImpl {
    // implement functions
};

Осталось две проблемы, главной из которых является реализация Figure.Я бы предложил создать некоторую функцию, например MakeLineFigure, которая будет возвращать новый Figure соответствующего типа.Вы могли бы также выставить FigureImpl конечному пользователю, но это кажется менее полезным.

Другая проблема заключается в том, что вы не можете больше делать обычные LineImpl с.Является ли это действительно проблемой, зависит от того, как вы собираетесь использовать класс.Вы можете сделать подобную оболочку с именем Line и дать ей operator Figure (это может быть неплохо; вам не нужны функции создания экземпляров), но в итоге это станет еще более шаблонным (возможно, вы могли бы сделать это с наследованием)где все новые классы не получают новых переменных-членов, а просто расширяют функции - я не пробовал).

Последняя проблема, которую я вижу, которая не зависит от того, какой маршрутвы выбираете, что вы позволяете линии умножить на плоскость.Возможно, это правильное поведение, но оно выглядит сомнительным.

Я не заметил, что умножение было скалярным, поэтому не обращайте внимания на эту последнюю часть.

0 голосов
/ 16 ноября 2011
Перегрузка

операторов, таких как оператор продукта, должна выполняться с большой осторожностью, поскольку (к сожалению) легко создать синтаксис, который противоречит здравому смыслу. Виртуализация таких перегруженных операторов не поможет. (Конечно, ваш код явно неисправен, как уже указывалось - ни Figure, ни Line не могут использоваться в качестве возвращаемого типа, поскольку оба являются абстрактными.)

0 голосов
/ 16 ноября 2011

Figure::operator* возвращает Figure по значению.
Line::operator* возвращает Line по значению.
Вам разрешено возвращать производный тип только в том случае, если он возвращается по указателю или по ссылке, но не по значению.

Мой код сейчас находится в той же точке, но я не понял, как обойти эту проблему, кроме как удалить виртуальные функции, которые возвращаются по значению.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...