2010-01-26 11 views
24

Considere el siguiente fragmento:Cambiar el modo de acceso de función en la clase derivada

struct Base 
{ 
    virtual ~Base() {} 

    virtual void Foo() const = 0; // Public 
}; 

class Child : public Base 
{ 
    virtual void Foo() const {} // Private 
}; 

int main() 
{ 
    Child child; 

    child.Foo(); // Won't work. Foo is private in this context. 

    static_cast<Base&> (child).Foo(); // Okay. Foo is public in this context. 
} 

¿Es esta C++ legal? "Esto" está cambiando el modo de acceso de la función virtual en la clase derivada.

+1

... ¿Compiló y ejecutó? – AndyG

+17

@SauceMaster, eso no es una muy buena indicación de si el código es legal en C++. Hay montones y montones de código C++ que se compilará y ejecutará, pero todavía invoca un comportamiento indefinido. Cambie los compiladores, los indicadores del compilador, la versión del compilador y el auge, deja de funcionar. – Glen

+0

De acuerdo con Glen. Es por eso que pregunté aquí. – hlx236sk

Respuesta

11

Sí, cambiar el modo de acceso en las clases derivadas es legal.

Esto es similares en la forma pero diferente en la intención de la Non-Virtual Interface idioma. Se da alguna justificación here:

El punto es que las funciones virtuales existen para permitir la personalización; a menos que también tengan que invocarse directamente desde el código de las clases derivadas, no hay necesidad de convertirlas en algo más que en privado.

cuanto a por qué usted realmente hacer algo public en base, pero private en derivados sin private o protected herencia es más allá de mí.

+0

Nice. Estaba usando este enfoque para una faceta de formateo, pero no estaba seguro de si esto era legal. ¡Gracias! – hlx236sk

+4

Esto es bastante contrario al NVI: la función de la clase base es pública + virtual, pero en NVI es privada + virtual y la función pública que la llama no es virtual. –

+0

@litb, Ah, whups. Bueno, arreglé el texto porque me perdí de la base pública virtual, derivada privada virtual. – MSN

5

Es perfectamente legal C++. Simplemente está definiendo un nuevo método en la clase Child.

Ahora hace lo que quiere que haga, esa es otra pregunta. Creo que el modo de acceso no forma parte de la firma del método, lo que significa que al llamar al método virtual Foo de Base eventualmente se llama al método Child's Foo.

Así que aquí está la conclusión: es legal C++ y funciona de la manera esperada.

No estoy teniendo en cuenta la línea child.Foo(); que no puede funcionar porque no hay duda de que está intentando acceder al método Foo() privado de Child.

4

Parece que compila y llama al método correcto.

Recuerde que los especificadores de acceso están ahí para ayudar a un programador disciplinado, no para evitar todos los intentos de eludirlo a toda costa.

En este caso particular, Child no tiene nada que hacer privada la función virtual anulada: ¿no se supone que implementa la interfaz pública de Base, por lo que se cumple la relación "is-a"? (Si no usó herencia pública, lo que significa "Niño es una base", su truco no funcionaría)

+1

"Recuerde que los especificadores de acceso están ahí para ayudar a un programador disciplinado, no para evitar todos los intentos de eludirlo a toda costa". es un gran punto – austinmarton

19

Esto es C legal ++, §11.6/1 dice:

acceso se comprueba en el punto llamada utilizando el tipo de la expresión utilizada para denotar el objeto para el que se llama la función miembro (B * en el ejemplo anterior ). El acceso de la función de miembro en la clase en la que se definió (D en el ejemplo anterior) es en general desconocido.

Como se anotó, Child::Foo() es por lo tanto sigue siendo accesible a través de la clase base, que es en la mayoría de los casos no deseado:

Child* c = new Child; 
Base* b = c; 
c->Foo(); // doesn't work, Child::Foo() is private 
b->Foo(); // works, calls Child::Foo() 

Básicamente, la declaración se hace referencia a la expresión dicta el modo de acceso - pero las funciones virtuales lo socavan como otra función, entonces el nombre puede ser invocado.

+0

Entonces, ¿qué implementación de 'Foo' se ejecuta en' b-> Foo() '? 'Child :: Foo' o' Base :: Foo'? Si 'Child :: Foo' rompe el control de acceso en la clase derivada. – ThomasMcLeod

+1

@ThomasMcLeod: el comentario en la misma línea dice cuál;) –

Cuestiones relacionadas