Mientras jugaba con la implementación de un operador de asignación virtual, terminé con un comportamiento extraño. No es un error del compilador, ya que g ++ 4.1, 4.3 y VS 2005 comparten el mismo comportamiento.¿Por qué la asignación virtual se comporta de manera diferente que otras funciones virtuales de la misma firma?
Básicamente, el operador virtual = se comporta de forma diferente que cualquier otra función virtual con respecto al código que se está ejecutando.
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 &)
}
El efecto es que el operador virtual = tiene un comportamiento diferente de cualquier otra función virtual con la misma firma ([0] en comparación con [1]), llamando a la versión base del operador cuando se llama a través objetos Derivados reales ([1]) o Referencias derivadas ([3]) mientras funciona como una función virtual regular cuando se llama a través de referencias Base ([2]), o cuando el valor l o el valor r son referencias Base y el otro Referencia derivada ([4], [5]).
¿Hay alguna explicación sensata para este comportamiento extraño?
No hay adivinando involucrado aquí. Las reglas son muy estrictas. – MSalters
Gracias. La respuesta real (tal como la publicaron tres personas) es que el operador generado por el compilador = para la clase Derivada llama implícitamente a Base :: operator =. Estoy marcando esto como 'respuesta aceptada' ya que fue el primero. –
'a = static_cast (b);» sería una forma de evitar los moldes de estilo C (que conllevan el riesgo de realizar accidentalmente un molde de reinterpretación) –