2

引自 C++ Primer 5th 19.2.1。dynamic_cast 运算符

dynamic_cast 具有以下形式:

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

其中 type 必须是类类型并且(通常)命名具有虚函数的类。在第一种情况下,e必须是一个有效的指针(第 2.3.2 节,第 52 页);第二,e 必须是左值;第三,e不能是左值。

在所有情况下,类型e必须是从目标类型公开派生的类类型、目标类型的公共基类或与目标类型相同。如果e具有这些类型之一,则转换将成功。否则,施法失败。
如果对指针类型的 dynamic_cast 失败,则结果为 0。如果对引用类型的 dynamic_cast 失败,则运算符抛出类型异常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++ 入门没有考虑到这一点。但是,此代码片段可以编译并运行而不会出现错误。入门有错吗?

4

3 回答 3

7

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

转换为基类不需要运行时转换操作。正如 TC 所说,它纯粹是一个静态构造。和引用的 TC 一样,它需要一个可访问的基础,而不是公共的。所以你的代码很好。

对于运行时转换(向下转换),C++ 标准对动态转换中涉及的操作数和类型提出了要求,以使其成功。该类必须是公开派生的,否则实现没有义务成功地沿继承链向下转换。我的意思是,理论上它可以使演员成功,但根据规范“运行时检查失败”,这并没有留下太多的余地。

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


如果我们将您的代码更改为向下而不是向上,这是一个甚至不构建的示例

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);
}

ABin的可访问基础foo,但演员阵容不正确。


将使入门重新回到课程的最小更改是将“从目标类型公开派生的类类型”转变为可访问地从目标类型派生的类类型”。由于公开的勘误表中没有任何此类内容,我们可以猜测这是一个尚未指出的编辑错误。

于 2018-03-20T10:22:38.263 回答
6

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

于 2018-03-20T10:29:11.167 回答
1

加粗的段落显然都是错误的。

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

  • type是一个类类型,它是 的静态确定类型的基类e。在这种情况下,dynamic_cast 或多或少与 static_cast 同义。特别是,type必须是e.
  • type是一个类类型,它不是 . 的静态确定类型的基类e。在这种情况下,会进行运行时检查。这进一步细分为向下转换交叉转换情况。它们之间的差异仅在多重继承和/或非公共继承的情况下才重要。在任何一种情况下,都type必须是 的完整对象的某个子对象的类型e

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

  • type不需要以任何方式与静态类型相关联e
  • type必须是动态类型的基类e或该类型本身(但不是它的适当派生类),并具有与可访问性和非歧义性相关的进一步限制。
于 2018-03-20T11:26:05.200 回答