c++ primer 是否在使用 `dynamic_cast` 时出错了?

Is the c++ primer making something wrong with the usage of `dynamic_cast`?

引自 C++ 入门第 5 期 19.2.1。 dynamic_cast 运算符

A dynamic_cast has the following form:

dynamic_cast<type*>(e)
dynamic_cast<type&>(e)
dynamic_cast<type&&>(e)

where type must be a class type and (ordinarily) names a class that has virtual functions. In the first case, e must be a valid pointer (§ 2.3.2, p. 52); in the second, e must be an lvalue; and in the third, e must not be an lvalue.

In all cases,the type of e must be either a class type that is publicly derived from the target type, a public base class of the target type, or the same as the target type. If e has one of these types, then the cast will succeed. Otherwise, the cast fails.
If a dynamic_cast to a pointer type fails, the result is 0. If a dynamic_cast to a reference type fails, the operator throws an exception of type bad_cast

不过,我在这里写了一段代码:

struct A {};
struct B : private A // note: *private* inheritance
{
  A* test() {
    return dynamic_cast<A*>(this);
  }
};

int main()
{
  B b;
  if(b.test()==nullptr)
      throw 1;
}

在上面的代码片段中,A只是B的私有基,c++入门没有考虑到。但是,此代码片段可以编译并且 运行 没有错误。是不是引子搞错了?

总的来说,这是引物部分的一个不幸的措辞。它将人们可以做的两种类型的演员组合成一个句子,然后结果说错了。

转换为基础 class,不需要运行时转换操作。 ,它是一个纯粹的静态结构。并且喜欢T.C。引用,它需要一个 accessbile 基础,而不是 public 基础。所以你的代码一切都很好。

对于运行时强制转换(向下强制转换),C++ 标准对动态强制转换中涉及的操作数和类型提出了要求,以使其成功。 class 必须是 publicly 派生的,否则实现没有义务在继承链中成功转换。我的意思是,理论上它可以使转换成功,但根据规范 "the runtime check fails",这不会留下太多余地。

但无论哪种方式,您的程序都没有导致编译失败的问题,也没有任何问题会导致任何类型的运行时错误。


如果我们将您的代码更改为向下转换而不是向上转换,这里是 example that doesn't even build:

struct A {};
struct B : private A // note: *private* inheritance
{
  A* test(B* p) {
    return dynamic_cast<A*>(p);
  }

  friend B* foo(A*);
};

B* foo(A* a) {
    return dynamic_cast<B*>(a);
}

int main()
{
  B b;
  *foo(&b);
}

AfooB 的可访问基数,但演员表是 ill-formed.


将入门课程带回课程的最小改动是将 "a class type that is publicly derived from the target type" 变为 "a class type that is accessibly derived from the target type" .由于 publicly available errata 中没有此类内容,我们可以猜测这是一个尚未指出的编辑错误。

A derived-to-base dynamic_cast 是静态的,而不是动态的,并且只需要在强制转换的上下文中可以访问基础(并且明确)。参见 [expr.dynamic.cast]/5

加粗的段落明显都是错误的

处理class类型的动态转换表达式在逻辑上可以细分为两种情况。

  • type 是 class 类型,它是 e 静态确定的 类型的基础 class。在这种情况下 dynamic_cast 或多或少与 static_cast 同义。特别是,type 必须是 e.
  • 类型的可访问且明确(但不一定 public)基 class
  • type 是一个 class 类型,它不是 e 静态确定 类型的基础 class。在这种情况下,会进行运行时检查。这进一步细分为 downcastcrosscast 情况。它们之间的差异仅在多重继承 and/or non-public 继承的情况下才重要。在这两种情况下,type 必须是 e 的完整对象的某个子对象的类型。

入门书从未说明它是指 e 的静态类型还是动态类型,但无论哪种情况,描述都是完全错误的。为了演员成功,

  • type 不需要以任何方式与 estatic 类型相关
  • type 必须是 edynamic 类型的基础 class 或该类型本身(但不是正确的派生 class),还有与可访问性和 non-ambiguity.
  • 相关的进一步限制