Записать (todo) после чего нажать клавишу tab kbd>
Вот как это происходит:
Если я изменю [1] на
a = *((Base*)&b);
, все будет работать так, как вы ожидаете. В Derived
есть автоматически сгенерированный оператор присваивания, который выглядит следующим образом:
Derived& operator=(Derived const & that) {
Base::operator=(that);
// rewrite all Derived members by using their assignment operator, for example
foo = that.foo;
bar = that.bar;
return *this;
}
В вашем примере компиляторы имеют достаточно информации, чтобы предположить, что a
и b
имеют тип Производный
, поэтому они решили использовать автоматически созданный выше оператор, вызывающий ваш. Вот как вы получили [1]. Мое приведение указателя заставляет компиляторы делать это по-вашему, потому что я говорю компилятору «забыть», что b
имеет тип Derived
, и поэтому он использует Base
. . 124] Аналогичным образом можно объяснить и другие результаты.
Если вы не предоставите соответствующий operator =
(т.е. правильный тип возвращаемого значения и аргумента), компилятор предоставит значение по умолчанию operator =
, которое перегружает любой пользовательский. В вашем случае он вызовет Base :: operator = (Base const &)
перед копированием производных элементов.
Проверьте эту ссылку , чтобы узнать, как operator = становится виртуальным.
В этом случае есть три оператора =:
Base::operator=(Base const&) // virtual
Derived::operator=(Base const&) // virtual
Derived::operator=(Derived const&) // Compiler generated, calls Base::operator=(Base const&) directly
Это объясняет, почему похоже, что Base :: operator = (Base const &) вызывается «виртуально» в случае [1]. Он вызывается из версии, созданной компилятором. То же относится и к случаю [3]. В случае 2 правый аргумент «bb» имеет тип Base &, поэтому Derived :: operator = (Derived &) не может быть вызван.
Пользовательский оператор присваивания не определен для класса Derived. Следовательно, компилятор синтезирует один, и оператор присваивания внутреннего базового класса вызывается из этого синтезированного оператора присваивания для производного класса.
virtual Base& operator=( Base const & ) //is not assignment operator for Derived
Следовательно, a = b; // [1] output: Base :: operator = (Base const &)
В производном классе оператор присваивания базового класса был переопределен, и, следовательно, переопределенный метод получает запись в виртуальной таблице производного класса. Когда метод вызывается через ссылку или указатели, тогда вызывается переопределенный метод производного класса из-за разрешения записи VTable во время выполнения.
ba = bb; // [2] outputs: Derived::operator=(Base const &)
==> внутренне ==> (Object-> VTable [оператор присваивания]) Получите запись для оператора присваивания в VTable класса, к которому принадлежит объект, и вызовите метод.