Во время игры с реализацией виртуального оператора присваивания я закончил смешное поведение. Это не сбой компилятора, поскольку 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 или r являются базовыми, а другое - производной ссылкой ([ 4], [5]).
Есть ли разумное объяснение этому нечетному поведению?