c++ - Clase base inaccesible a pesar de la amistad.
inheritance friend (3)
Hay un montón de preguntas con respecto a este error y todas las respuestas parecen implicar que es imposible bajar de opinión. Solo que esta respuesta menciona la amistad como posible solución, al menos como la entiendo. Sin embargo, el siguiente código (cosas irrelevantes eliminadas para mayor claridad) no se compila:
class C;
class A {
friend class C; // this does not help
};
class B : protected A {
friend class C; // this does not help either
};
class C {
public:
void foo(A* a) {};
};
B b;
C c;
void bar()
{
c.foo(&b); // this produces error: class A is an inaccessible base of B
}
¿Por qué la amistad no funciona en una referencia? Después de todo, "C" es perfectamente capaz de llamar a los métodos protegidos de "A" a través de un puntero a "B".
El error completo es
prog.cc: In function ''void bar()'':
prog.cc:20:13: error: ''A'' is an inaccessible base of ''B''
20 | c.foo(&b);
El problema es que la conversión de
B*
a
A*
(la que requiere amistad) no ocurre en una función miembro de
C
, sino en el contexto del código que contiene
c
(es decir, la
bar()
funciones no relacionada
bar()
).
Funcionaría bien si creara una función miembro en
C
aceptando un
B*
y luego llamó a
foo()
desde dentro.
Eso haría que la conversión ocurriera dentro del contexto de
C
que tiene los derechos de acceso necesarios (gracias a la amistad).
En el ámbito global, B no es visible como A, debido a la herencia protegida.
Sólo la clase B, las clases heredadas de B y la clase C (porque la relación de amistad) "sabe" que B está heredando A. Pero el resto del mundo (incluido el alcance global) no lo hace ".
Así que para lograr lo que quieres, puedes llamar
c.foo(&b)
dentro del alcance de C, por ejemplo, usando alguna función de envoltura, algo como (aunque es una mala decisión de diseño):
#include <iostream>
#include <cstdlib>
class C;
class A {
friend class C; // this does not help
};
class B : protected A {
friend class C; // this does not help either
};
class C {
public:
void foo() {
B b;
foo(&b); // this call is OK within C-scope
}
private:
void foo(A* /*a*/) {
std::cout << "C::foo(A* a)/n";
};
};
int main()
{
std::cout << "Hello, Wandbox!" << std::endl;
B b;
C c;
//c.foo(&b); // this produces error: class A is an inaccessible base of B
c.foo(); // this is calling c.foo(A*) internally
}
o live :
Su código es equivalente a esto:
B b;
C c;
A * a = &b; // <- This cast produces the error
c.foo(a);
No puedes lanzar
&b
como
A*
ya que la clase base está protegida, independientemente de la amistad de
C