为什么C++需要公共继承,忽略朋友声明,才能使动态向下工作?

Why C++ requires public inheritance, ignoring friend declarations, to make dynamic downcast working?

本文关键字:动态 工作 声明 C++ 为什么 继承 朋友      更新时间:2023-10-16

这里我们有一个类B,继承自类A,它有一个friendC。作为朋友,C应该可以访问B中的所有内容,包括A基类。

为了测试它,

  1. 首先,我们创建一个B实例。
  2. 我们把它的地址改成一个A*
  3. 然后我们尝试再次用dynamic_cast<>将其向下投射以B*.

预期结果是取回原始B实例的地址。

#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= %pn", b);
A *a = static_cast<A*>(b);
printf("a= %pn", a);
B *bb = dynamic_cast<B*>(a);
printf("bb=%pn", bb);
delete b;
};
};
int main() {
C c;
c.doit();
return 0;
};

类似情况下的常见问题,即基类必须是多态的(这里由其空的虚拟析构函数保证(,在这里得到了解决。

但是,动态转换仍然不起作用:bb应该具有与b相同的地址。

我的实验表明,如果ABpublic基类,那么使其工作的唯一方法。但。。。CB的朋友。即使protected它也无法正常工作.

为什么会这样?

如果重要的话,我使用 gcc-8。

将"dynamic_cast"视为全局函数。 "朋友C;"将友谊交给"C类"而不是"dynamic_cast"。

成员访问检查在编译时进行。

dynamic_cast检查运行时的基本可访问性。RTTI 具有基本的可访问性信息(请参阅 MS 实现 rtti.cpp; __RTDynamicCast(,但没有友谊。

总结评论中的有用信息和引用资源,可以写一个自我答案。

首先,friend声明是没有问题的:friend仅影响声明它的类的成员的可访问性,而不影响其基类。

其次,可访问性签入C++进入编译时间。但是dynamic_cast的可访问性检查发生在运行时。这种可访问性检查的限制要严格得多,并且只有在继承public时才能发生dynamic_cast

其可能的原因是,正确执行此操作可能需要针对不同的访问级别使用不同的 rtti 表。