使用`dynamic_cast`时c ++底漆是否有问题?

big*_*iao 2 c++ dynamic-cast access-control private-inheritance

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

dynamic_cast具有以下形式:

dynamic_cast<type*>(e)
dynamic_cast<type&>(e)
dynamic_cast<type&&>(e)
Run Code Online (Sandbox Code Playgroud)

其中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;
}
Run Code Online (Sandbox Code Playgroud)

在上面的代码片段中,A它只是一个私有基础B,c ++入门没有考虑到它.但是,此代码段可以编译并运行而不会出错.底漆有错吗?

Sto*_*ica 6

这一切都是引物部分的一个不幸的措辞.它将两种类型的演员阵容组合成一个句子,然后错过了结果.

转换为基类,不需要运行时强制转换操作.它是,因为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);
}
Run Code Online (Sandbox Code Playgroud)

A是的可访问基地Bfoo,然而,是形成不良的铸造.


将引物重新引入过程的最小变化是将" 从目标类型公开派生的类类型"变为" 从目标类型可访问地派生的类类型".由于在公开的勘误表中没有任何类型,我们可以猜测这是一个尚未被指出的编辑错误.


T.C*_*.C. 6

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