puro - sobreescribir metodo c++
Función virtual pública derivada privada en C++ (3)
Estaba tratando de averiguar qué sucede cuando una clase derivada declara que una función virtual es privada. El siguiente es el programa que escribí.
#include <iostream>
using namespace std;
class A
{
public:
virtual void func() {
cout<<"A::func called"<<endl;
}
private:
};
class B:public A
{
public:
B()
{
cout<<"B constructor called"<<endl;
}
private:
void func() {
cout<<"B::func called"<<endl;
}
};
int main()
{
A *a = new B();
a->func();
return 0;
}
Sorprendentemente (para mí) la salida fue:
B constructor called
B::func called
¿No está esto violando el conjunto de acceso privado para esa función? ¿Es este el comportamiento esperado? ¿Se trata de una solución estándar o laguna? ¿Se omiten los niveles de acceso al resolver llamadas de función a través de VTABLE?
Cualquier información sobre este comportamiento sería de gran ayuda.
Además, se mencionó que una anulación privada de un miembro virtual evitaría que otras clases lo heredaran. Incluso esto está teniendo problemas. Modificando el programa anterior para incluir:
class C: public B
{
public:
void func() {
cout<<"C::func called"<<endl;
}
};
y el principal programa de pruebas para:
int main()
{
A *a = new C();
a->func();
return 0;
}
la salida es:
C::func called
Bueno, estás llamando a A::func()
que es public
aunque en un objeto B
está anulado por B::func()
. Este es un patrón común con las siguientes implicaciones:
func
no está destinado a ser llamado en objetosB
derivadosfunc
no puede ser anulada en clases derivadas deB
El comportamiento es correcto. Cada vez que declara su función como "virtual", le indica al compilador que genere una llamada virtual, en lugar de la llamada directa a esta función. Cada vez que anula la función virtual en la clase descendiente, especifica el comportamiento de esta función (no cambia el modo de acceso para aquellos clientes que confían en la interfaz "principal").
Cambiar el modo de acceso para la función virtual en la clase descendiente significa que desea ocultarlo de aquellos clientes, que usan la clase descendiente directamente (que dependen de la interfaz del "niño").
Considera el ejemplo:
void process(const A* object) {
object->func();
}
La función "proceso" se basa en la interfaz del padre. Se espera que funcione para cualquier clase, derivada del público de A. No puede derivar públicamente B de A (que dice "cada B es A"), pero puede ocultar una parte de su interfaz. Aquellos que esperan "A" deben recibir una "A" completamente funcional.
Este es un comportamiento bien definido. Si a
fuera una B*
esto no se compilaría. El motivo es que el compilador resuelve el acceso de los miembros de forma estática, no dinámicamente en tiempo de ejecución. Muchos libros de C ++ sugieren que evites la codificación de esta manera porque confunde a los codificadores menos experimentados.