Почему виртуальное назначение ведет себя иначе, чем другие виртуальные функции с одинаковой сигнатурой?

Играя с реализацией оператора виртуального присваивания, я закончил с забавным поведением. Это не сбой компилятора, поскольку g ++ 4.1, 4.3 и VS 2005 ведут себя одинаково.

По сути, виртуальный оператор = ведет себя иначе, чем любая другая виртуальная функция, в отношении кода, который фактически выполняется.

struct Base {
   virtual Base& f( Base const & ) {
      std::cout << "Base::f(Base const &)" << std::endl;
      return *this;
   }
   virtual Base& operator=( Base const & ) {
      std::cout << "Base::operator=(Base const &)" << std::endl;
      return *this;
   }
};
struct Derived : public Base {
   virtual Base& f( Base const & ) {
      std::cout << "Derived::f(Base const &)" << std::endl;
      return *this;
   }
   virtual Base& operator=( Base const & ) {
      std::cout << "Derived::operator=( Base const & )" << std::endl;
      return *this;
   }
};
int main() {
   Derived a, b;

   a.f( b ); // [0] outputs: Derived::f(Base const &) (expected result)
   a = b;    // [1] outputs: Base::operator=(Base const &)

   Base & ba = a;
   Base & bb = b;
   ba = bb;  // [2] outputs: Derived::operator=(Base const &)

   Derived & da = a;
   Derived & db = b;
   da = db;  // [3] outputs: Base::operator=(Base const &)

   ba = da;  // [4] outputs: Derived::operator=(Base const &)
   da = ba;  // [5] outputs: Derived::operator=(Base const &)
}

Эффект заключается в том, что виртуальный оператор = имеет поведение, отличное от любой другой виртуальной функции с той же сигнатурой ([0] по сравнению с [1]), вызывая базовую версию оператора при вызове через реальные производные объекты ([1] ) или производные ссылки ([3]), когда она работает как обычная виртуальная функция при вызове через базовые ссылки ([2]), или когда lvalue или rvalue являются базовыми ссылками, а другая - производной ссылкой ([4], [5]).

Есть ли разумное объяснение этому странному поведению?

Ответы на вопрос(5)

Ваш ответ на вопрос