C++ 入门书在使用 `dynamic_cast` 时有什么问题吗? [英] Is the c++ primer making something wrong with the usage of `dynamic_cast`?

查看:32
本文介绍了C++ 入门书在使用 `dynamic_cast` 时有什么问题吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

<块引用>

dynamic_cast 具有以下形式:

dynamic_cast(e)dynamic_cast(e)dynamic_cast

<块引用>

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

在所有情况下,e 的类型必须是公共派生自的类类型目标类型,目标类型的公共基类,或与目标相同类型.如果 e 具有这些类型之一,则转换将成功.否则,转换失败.
如果对指针类型的 dynamic_cast 失败,则结果为 0.如果对指针类型的 dynamic_cast引用类型失败,操作符抛出 bad_cast

类型的异常

然而,我在这里写了一个代码片段:

struct A {};struct B : private A//注意:*private* 继承{一个测试() {return dynamic_cast(this);}};int main(){乙乙;if(b.test()==nullptr)扔1;}

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

解决方案

总的来说,这是引物部分令人遗憾的措辞.它将两种类型的演员组合成一个句子,然后结果说错了.

转换为基类,不需要运行时转换操作.它是,作为 T.C.说,纯粹是一个静态结构.就像 T.C.引用,它需要一个可访问性基础,而不是公共基础.所以你的代码都很好.

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

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

<小时>

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

struct A {};struct B : private A//注意:*private* 继承{A* 测试(B* p) {返回 dynamic_cast(p);}朋友 B* foo(A*);};B* foo(A* a) {返回 dynamic_cast(a);}int main(){乙乙;*foo(&b);}

AfooB 的可访问基础,但是,转换格式不正确.

<小时>

使入门课程重回正轨的最小变化是将从目标类型公开派生的类类型"变成a从目标类型可访问派生的类类型".由于公开勘误,我们可以猜测这是一个尚未指出的编辑错误.

Quoted from C++ Primer 5th 19.2.1. The dynamic_cast Operator

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

However,here I've written a code snippet:

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

In the code snippet above, A is just a private base of B, which is not taken into account by the c++ primer. However, this code snippet could be compiled and run without error. Has the primer made a mistake?

解决方案

This is all in all an unfortunate phrasing on the primers part. It bunched the two types of casts one can do into one sentence, and then misspoke as a result.

Casting to a base class, doesn't require a runtime cast operation. It is, as T.C. says, purely a static construct. And like T.C. quoted, it requires an accessbile base, not public one. So your code is all good and well.

For a runtime cast (a downcast) the C++ standard places a requirement on the operand and the types involved in a dynamic cast in order for it to succeed. The class must be publicly derived, otherwise the implementation isn't obligated to make a successful cast down the inheritance chain. I mean, it could in theory make the cast successful, but according to the specification "the runtime check fails", which doesn't leave much leeway.

But either way there's nothing wrong in your program that would make it fail to compile, nor is there anything there that would cause any sort of runtime error.


If we change your code to cast down, and not cast up, here's an 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);
}

A is an accessible base of B in foo, and yet, the cast is ill-formed.


The minimal change which will bring the primer back on course is to turn "a class type that is publicly derived from the target type" into "a class type that is accessibly derived from the target type". Since there's nothing of the sort in the publicly available errata, we can guess it's an editorial mistake that is yet to be pointed out.

这篇关于C++ 入门书在使用 `dynamic_cast` 时有什么问题吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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