Как стать автором
Обновить

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

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


Прошу прощения, можно пояснить эту мысль (желательно, с иллюстрирующим кодом)?
class Base {
public:
Base &operator =(const Base &) { cout << «A» << endl; return *this; }
};
class X: public virtual Base { };
class Y: public virtual Base { };
class XY: public X, public Y { };

XY a, b;
a = b;

Этот код, собранный в Visual Studio 2010, печатает две буквы 'A'. Но это не значит, что он всегда и везде будет печатать 'A' два раза. Вызов оператора = может произойти и 1 раз.
X::operator =(*this);
Y::operator =(*this);

не?
Да, я могу назвать как минимум одно: подмешивание интерфейсов.

История из жизни :)
Я тут недавно столкнулся с проблемой, когда пытался так «подмешивать» интерфейсы. Командой составили пару интерфейсов, в которых присутствовали методы с одинаковыми именами и сигнатурами.
По задумке предполагалось, что эти методы могут вести себя по-разному в объекте, реализующем оба интерфейса одновременно, в зависимости от того, через какой интерфейс к нему обращаются.
Т.е., грубо говоря, хотели реализовать вызовы вида:
Object::Interface1.Method() и Object::Interface2.Method() с различным поведением.
Выяснилось, что по стандарту так делать нельзя.
Есть несколько вариантов обойти это ограничение, но наследование перестает быть чисто абстрактным («интерфейсным»).
Или становится непереносимым, если использовать ключевое слово __interface в MSVC.
А зачем такое нужно? Правда, интересно.
Да не нужно особо :)
Было два интерфейса Reader/Writer, у обоих методы типа Seek и т.п.
Назывались одинаково.
Если делать Storage с обоими интерфейсами и независимыми курсорами на чтение/запись, на стандартном C++ без бубна не обойтись.
Мы тупо переименовали методы с совпадающими сигнатурами.
А так я сам смотрел и на RSDN спрашивал — делаются redirect-прослойки или в случае MSVC можно использовать ключевое слово __interface вместо абстрактного класса.
Хм, не совсем понял: dynamic_cast — плохо пахнет? Согласно «чистому» подходу reinterpret_cast и static_cast тоже ось зла :)
А вообще нужно ли упоминать об reinterpret_cast для родственных классов? По определению — его тут использовать вообще не надо.
static_cast — конечно можно использовать для приведения от базового к дочернему, но не приветствуется. Разве не так?
А dynamic_cast как раз и должен использоваться разных игр с иерархиями, в частности преобразования указателя/ссылки на базовый класс к указателю/ссылке на дочерний. При этом производит все необходимые проверки. (но есть нюансы).

Поправьте, если я не прав. Если эта статья обучающая, то считаю, что учесть эти моменты было бы важно.
Да, dynamic_cast плохо пахнет. Если такая возможность есть в языке, это не значит, что ей надо пользоваться на полную. Как правило, наличие dynamic_cast, свидетельствует о плохой иерархии классов и неверных методах работы с ними. dynamic_cast это костыль. Он медленный и часто приводит к лесу if (dynamic_cast<>())… else if (dynamic_cast<>()) else if (dynamic_cast<>()). А именно от этого и должна избавлять грамотная иерархия классов с виртуальными функциями.
См. например на эту тему: Стефан К. Дьюхерст. Скользкие места C++. Советы:
  1. Совет 98. Задание «интимных» вопросов объекту.
  2. Совет 99. Опрос возможностей.


P.S. О том что reinterpret_cast и static_cast это хорошо, я не говорил. Я просто привел пример, что с дуру и reinterpret_cast, можно заставить компилятор сделать бессмысленное приведение типа.
Я не хотел задеть, поспорить или оскорбить. Мне сильно бросилось в глаза пункт с «кастами» (с дуру наделать можно и не такого, согласитесь), по этому и оставил заметку.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий