问题
Here we have a class B
, inherited from class A
, and it has a friend
class C
. Being a friend, C
should have access to everything in B
, including the A
base class.
To test it,
- first we create a
B
instance. - we upcast its address to an
A*
- then we try downcast it with
dynamic_cast<>
again toB*
.
The expected result is to get back the address of the original B
instance.
#include <cstdint>
#include <cstdio>
class A {
public:
virtual ~A() {};
};
class C;
class B : protected A { // <- this should be public to work! Why?
friend C;
};
class C {
public:
void doit() {
B *b = new B();
printf("b= %p\n", b);
A *a = static_cast<A*>(b);
printf("a= %p\n", a);
B *bb = dynamic_cast<B*>(a);
printf("bb=%p\n", bb);
delete b;
};
};
int main() {
C c;
c.doit();
return 0;
};
The common problem in similar cases, that the base class has to be polymorph (which is guaranted here by its empty virtual destructor), is here solved.
However, the dynamic casting still does not work: bb
should have the same adress as b
.
My experiments show, the only way to make it working, if A
is a public
base class of B
. But... C
is a friend of B
. It does not work even as protected
.
Why is it so?
I use gcc-8, if it matters.
回答1:
Summarizing the useful infos and cited resources in the comments, a self-answer can be written.
First, the friend
declaration is a no-issue: friend
affects only the accessibility of the members of the class where it is declared on, but not its base class(es).
Second, accessibility check in C++ goes in compilation time. But the accessibility check of dynamic_cast
happens in runtime. This accessibility check is far more restrictive, and the dynamic_cast
can happen only if the inheritance is public
.
Its likely reason is that doing it correctly would probably require different rtti tables for the different access levels.
来源:https://stackoverflow.com/questions/62430684/why-c-requires-public-inheritance-ignoring-friend-declarations-to-make-dynam