Почему виртуальные операторы присваивания являются «банкой червей»?

#c

#c

Вопрос:

В моем учебнике говорится, что виртуальные операторы присваивания «открывают новую банку червей, выходящую за рамки учебного пособия».

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

Что это значит? Можете ли вы объяснить, о каких проблемах говорится в книге, на небольшом примере? Почему виртуальные операторы присваивания являются особенными?

Комментарии:

1. В общем, оператор присваивания и наследование вместе — плохая идея, так много всего может пойти не так, если не учитывать это должным образом, например, усечение объекта. И это перед добавлением виртуального наследования в микс, который умножает особые случаи, чтобы получить право.

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

3. отредактировано, запрос ссылок или сторонних ресурсов считается оффтопическим

4. Найдите в Интернете «C object slicing».

5. Хорошо, я сделаю, спасибо @ThomasMatthews ! 🙂

Ответ №1:

Давайте возьмем классический пример формы:

 class Shape
{
  public: virtual bool operator==(const Shape amp; s) const = 0;
};

class Rectangle : public Shape
{
  public: bool operator==(const Shape amp; s) const
  { /*...*/ }
};

class Circle : public Shape
{
  public: bool operator==(const Shape amp; s) const
  { /*...*/ }
};  
  

Теперь начинается самое интересное.

 Rectangle r;
Circle c;
Shape * p_shape1 = amp;r; // This is legal.
Shape * p_shape2 = amp;c; // So is this.

// What happens here????
if (r == *p_shape2)
{
  //...
}
  

ИМХО, операторы не должны наследоваться. Нет никакой гарантии, что операторы Child1 будут переданы экземплярам Child1; Они могут быть переданы экземплярам Child` или Child3 или даже экземплярам GrandChild1.

Комментарии:

1. С присваиванием еще интереснее!

2. Это не относится к операторам. Функция определена так, чтобы принимать Shape constamp; аргумент, и это все, что она может принять. Написание виртуального оператора равенства обычно включает dynamic_cast . В любом случае, однако, OP спрашивал об операторе присваивания.