2010-11-04 9 views
6

terminé de codificación (Con un poco de ayuda) algo como esto ayer:¿Cómo y por qué es posible cambiar el nivel de acceso de un miembro?

#include <iostream> 

using namespace std; 

class A 
{ 
    public: 
     virtual void foo(){cout << "A::foo\n";} 
}; 

class B : private A 
{ 
    private: 
     virtual void foo(){ cout << "B::foo\n";} 
     void DoSomething(SomeOtherClass& o){o.DoSomething(*static_cast<A*>(this));} 
}; 

He intentado cambiar el método de la herencia:

class B : public A 
{ 
    private: 
     virtual void foo(){ cout << "B::foo\n";} 
}; 

int main() 
{ 
    A* a = new B; 
    a->foo(); 
} 

Esto todavía funciona. Esperaba un error de tiempo de compilación. Por favor, dime por qué es posible y cuáles son los posibles usos. Conozco un uso debido al primer escenario: puede exponer diferentes interfaces para diferentes clases.

EDIT:

En el segundo caso, la salida se B::foo.

+0

¿Dónde esperabas el error?En la declaración de la función como privada? ¿O en la llamada de la función? –

+0

Estoy intrigado. Esperando una respuesta que explique los posibles usos de esta característica (?). Un uso podría ser forzar al programador a crear una instancia de la clase B como un puntero a la clase base A para usar su interfaz. Pero por qué eso sería A Good Thing, no sé. – manneorama

+0

@PigBen: esperaba el error en la definición de 'foo' en' B' en el segundo caso. – nakiya

Respuesta

1

Puede que no conteste todas sus preguntas directamente, sin embargo, decidí ponerlo aquí para referencia futura. También tómenlo con un poco de sal, ya que esto se basa en mi comprensión de los eventos que han sucedido en el mundo de C++ Standard, en lugar de los reales.

Lea this. No tengo el ARM conmigo, pero el artículo proporciona los detalles necesarios.

Nota 115 en C++ 0x dice

115) declaraciones de acceso son obsoleto; las declaraciones de uso de miembros (7.3.3) proporcionan un medio mejor de haciendo las mismas cosas. En versiones anteriores de del lenguaje C++, las declaraciones de acceso eran más limitadas; ellos se generalizaron y se hicieron equivalentes a las declaraciones de uso en el interés de simplicidad. Los programadores son alentados a usar declaraciones de uso, en lugar de las nuevas capacidades de declaraciones de acceso, en el nuevo código.

En resumen:

creo que el ARM prohibido inicialmente:

Una declaración de acceso no puede utilizarse para restringir el acceso a un miembro que es accesible en la clase base, tampoco puede usarse para habilitar el acceso a un miembro al que no se puede acceder en la clase base .

Pero más tarde, supongo que cuando la norma evolucionó this was eventually allowed

+0

"eventualmente permitido", bueno, ahora están obsoletos. esta respuesta tuvo una cita mejor: http://stackoverflow.com/questions/2084801/c-using-declaration-scope-and-access-control –

3
using namespace std; 

class A 
{ 
    public: 
     virtual void foo(){cout << "A::foo\n";} 
}; 

class B : public A 
{ 
    private: 
     virtual void foo(){ cout << "B::foo\n";} 
}; 

int main() 
{ 
    A* a = new B; 
    a->foo(); 
} 

Esto funciona porque en tiempo de compilación el compilador sólo puede ver que a es un puntero a la clase base A y foo() es un método público siendo llamado en a, que es perfectamente válido. La vinculación virtual ocurre dinámicamente en el tiempo de ejecución después de la compilación, este enlace virtaul decide que la llamada real es a B::foo() y no a A::foo() que es la penalidad de rendimiento de usar virtualismo.

+0

Es fácil ver por qué funciona. Pero hubiera tenido mucho más sentido si no se hubiera permitido que foo() se convirtiera en privado en B. Así que creo que la pregunta es, ¿cuál es la razón detrás de esa decisión de diseño? –

+0

@kotlinski: Hay un patrón de diseño muy famoso llamado "patrón de método de plantilla" que hace uso de esta lógica. Por favor revisa eso. –

+1

No veo la conexión entre esto y el patrón de diseño del método de la plantilla. – nakiya

Cuestiones relacionadas