2010-08-31 16 views
29
#include<iostream> 

using namespace std; 
class base 
{ 
public: 
    virtual void add() { 
     cout << "hi"; 
    } 
}; 

class derived : public base 
{ 
private: 
    void add() { 
     cout << "bye"; 
    } 
}; 

int main() 
{ 
    base *ptr; 
    ptr = new derived; 
    ptr->add(); 
    return 0; 
} 

salida es bye¿Por qué puedo acceder a una función derivada de miembro privado a través de un puntero de clase base a un objeto derivado?

no tengo un problema con cómo se implementa esto. Entiendo que uses vtables y vtable de derived contiene la dirección de la nueva función add(). Pero add() es privado, ¿no debería el compilador generar un error cuando intento acceder a él fuera de la clase? De alguna manera, no parece correcto.

+4

Los especificadores de anulación y acceso son conceptos ortogonales. – sbi

+0

vtables son un detalle de implementación. –

Respuesta

32

add() sólo es privado en derived, pero el tipo estático lo que tienes es base* - por lo tanto se aplican las restricciones de acceso de base.
En general, ni siquiera puede saber en tiempo de compilación cuál será el tipo dinámico de un puntero a base, podría, p. Ej. cambio basado en la entrada del usuario.

Esto es por C++ 03 §11.6:

Las reglas de acceso (cláusula 11) para una función virtual están determinados por su declaración y no se ven afectados por las normas para una función que más tarde lo invalida.
[...] El acceso se verifica en el punto de llamada utilizando el tipo de expresión utilizada para indicar el objeto para el que se llama a la función miembro [...]. El acceso de la función miembro en la clase en la que se definió [...] no se conoce en general.

+0

+1 - Gracias por el comentario clarificador de mi respuesta. –

+0

@Georg Fritzsche Puede darme el enlace de C++ 03 desde donde copió este enlace. Busqué en Google pero no encontré, quiero estudiar C++ –

+0

@Jai: ["¿Dónde encuentro los documentos estándar actuales de C o C++?"] (Http://stackoverflow.com/questions/81656/where-do-i-find -the-current-c-or-c-standard-documents) –

5

Para añadir un poco a la respuesta de Georg:

Recuerde que el compilador no tiene control sobre y no puede garantizar nada acerca de las clases derivadas. Por ejemplo, podría enviar mi tipo en una biblioteca y derivarlo en un programa completamente nuevo. ¿Cómo se supone que el compilador de la biblioteca sabe que derivado podría tener un especificador de acceso diferente? El tipo derivado no existía cuando se compiló la biblioteca.

Para soportar esto, el compilador debería conocer los especificadores de acceso en tiempo de ejecución y lanzar una excepción si intenta acceder a un miembro privado.

10

Los modificadores de acceso, como public, private y protected solo se aplican durante la compilación. Cuando llama a la función a través de un puntero a la clase base, el compilador no sabe que el puntero apunta a una instancia de la clase derivada. De acuerdo con las reglas que el compilador puede inferir de esta expresión, esta llamada es válida.

Suele ser un error semántico para reducir la visibilidad de un miembro en una clase derivada. Los lenguajes de programación modernos como Java y C# se niegan a compilar dicho código, porque un miembro que es visible en la clase base siempre es accesible en la clase derivada a través de un puntero base.

+1

+1 La mejor respuesta. –

Cuestiones relacionadas