c++ - simple - tipos de herencia en java
Error con la herencia de clase anidada (5)
Cita de cppreference :
Un nombre que es privado de acuerdo con la búsqueda de nombre no calificado, puede ser accesible a través de la búsqueda de nombre calificado
Con esto en mente, veamos cómo funcionaría la búsqueda de nombres no calificados para el primer ejemplo:
class A {};
class B : private A {};
class C : private B
{
public:
class D : private A {}; // Error here
};
-
Ase busca dentro del alcance deCSi se hubiera definido allí, no habría ningún problema. - Se da cuenta de que
Aes heredado de forma privada por su claseB(privada) de base y, por lo tanto, arroja un error de compilación. Clang dice:note: constrained by private inheritance here: class B : private A {};
De nuevo, según la cita, debería funcionar, si usa un nombre completamente calificado, como lo ha demostrado
class D : private ::A {};
Y en cuanto a tu último ejemplo:
class A {};
class C : private A
{
public:
class D : private A {};
};
Funciona porque la búsqueda de nombre funciona para todos los nombres que forman parte de la misma clase. Para citar de cppreference nuevamente:
Todos los miembros de una clase (cuerpos de funciones miembro, inicializadores de objetos miembros y todas las definiciones de clase anidadas) tienen acceso a todos los nombres a los que puede acceder una clase.
class A {};
class B : private A {};
class C : private B
{
public:
class D : private A {}; // Error here
};
Este código proporciona el siguiente error (en VS 2013):
nested.cpp (8): error C2247: ''A'' no accesible porque ''B'' usa ''privado'' para heredar de ''A''
Se soluciona si cambio la definición de D así:
class D : private ::A {};
¿Es este comportamiento correcto, y si es así por qué?
Al principio pensé que era porque C hereda en privado de B lo que ocultaría las clases base. Pero si elimino la clase B "hombre medio" y solo uso esto:
class A {};
class C : private A
{
public:
class D : private A {};
};
El error desaparece
Ejemplo de cppreference :
class A { };
class B : private A { };
class C : public B {
A* p; // error: unqualified name lookup finds A as the private base of B
::A* q; // OK, qualified name lookup finds the namespace-level declaration
};
Con la herencia privada, los miembros públicos y protegidos de la clase base se convierten en miembros privados de la clase derivada.
class B : private A {};
class C : private B
{
public:
class D : private A {}; // Error because all members of A is private to B so what
//would be the use of this private inheritance if you can''t access any of A''s member.
};
Mientras
class D :private ::A {};
funciona porque los miembros de A se toman directamente del espacio de nombres global, lo que permite a D tener acceso a los miembros protegidos y públicos de A
Es una cuestión de alcances durante la búsqueda de nombres:
Cuando usas
::Aes un nombre totalmente calificado, por lo tanto, te estás refiriendo explícitamente al espacio de nombres global y seleccionandoAdesde allí.Cuando heredas de
A,C(déjame decir) veAy puedes referirte directamente al nombreAdentro deCcon un nombre no calificado.Cuando hereda de
B,CveByAes privado en su alcance. Es privado, pero existe. ComoAes un nombre no calificado y se busca ante todo en ese ámbito, resulta ser encontrado e inaccesible, por lo tanto, el error.
Una parte crucial para la comprensión, que no se explica explícitamente en las otras respuestas, es la siguiente:
El nombre de una clase se inyecta en el alcance de las clases.
Es decir, si tiene
class A {};
entonces puede referirse a la clase A no solo por el nombre ::A sino también por el nombre A::A Tenga en cuenta que a pesar de describir la misma clase, esos no son del mismo nombre, ya que están en diferentes ámbitos.
Ahora cuando en el ámbito de A o una clase que se deriva directa o indirectamente de A , la búsqueda no calificada encontrará A::A lugar de ::A (a menos que A::A esté oculto por otro nombre).
Además, a diferencia de otros lenguajes, C ++ no oculta los nombres privados de los ámbitos donde no puede acceder a ellos, sino que usa los especificadores de acceso solo como permiso para usar el nombre. Además, esos permisos están vinculados al nombre, no a la entidad nombrada (en este caso, la clase).
Entonces en su código, en la búsqueda no calificada de A el compilador encuentra el nombre C::B::A::A que oculta el nombre ::A , y luego verifica el permiso de acceso y encuentra que este nombre es privado en el contexto actual, ya que es un nombre en el ámbito de C::B::A que no se puede acceder desde C ya que A es una clase base privada de B
clase D: privada :: A {}; Cuando hereda de B, C ve B y A es privado en su alcance. Es privado, pero existe. Como A es un nombre no calificado y se busca ante todo en ese ámbito, resulta ser encontrado e inaccesible, por lo tanto, el error.