为什么C ++要求公共继承,而忽略朋友声明,才能使动态向下转换有效? [英] Why C++ requires public inheritance, ignoring friend declarations, to make dynamic downcast working?

查看:54
本文介绍了为什么C ++要求公共继承,而忽略朋友声明,才能使动态向下转换有效?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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.

要对其进行测试,

  1. 首先,我们创建一个 B 实例.
  2. 我们将其地址上传到 A *
  3. 然后我们尝试再次使用 dynamic_cast<> 将其向下转换为 B * .
  1. first we create a B instance.
  2. we upcast its address to an A*
  3. then we try downcast it with dynamic_cast<> again to B*.

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

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.

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

However, the dynamic casting still does not work: bb should have the same adress as b.

我的实验表明,如果 A B public 基类,那么唯一可行的方法.但是... C 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.

为什么会这样?

如果需要的话,我使用gcc-8.

I use gcc-8, if it matters.

推荐答案

总结注释中的有用信息和引用的资源,可以编写自我答案.

Summarizing the useful infos and cited resources in the comments, a self-answer can be written.

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

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).

第二,C ++中的可访问性检查在编译时进行.但是 dynamic_cast 的可访问性检查是在运行时进行的.此可访问性检查的限制要严格得多,并且只有在继承为 public 的情况下,才会发生 dynamic_cast .

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.

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

Its likely reason is that doing it correctly would probably require different rtti tables for the different access levels.

这篇关于为什么C ++要求公共继承,而忽略朋友声明,才能使动态向下转换有效?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆