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

喜你入骨 提交于 2019-12-12 17:27:06

问题


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?


回答1:


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.




回答2:


A derived-to-base dynamic_cast is static, not dynamic, and only requires the base to be accessible in the context of the cast (and unambiguous). See [expr.dynamic.cast]/5.




回答3:


The bolded passages are all obviously wrong.

The dynamic cast expression that deals with class types can be logically subdivided in two cases.

  • type is a class type which is a base class of the statically determined type of e. In this case dynamic_cast is more or less synonymous with static_cast. In particular, type must be an accessible and unambiguous (but not necessarily public) base class of the type of e.
  • type is a class type which is not a base class of the statically determined type of e. In this case, a runtime check takes place. This is further subdivided to the downcast and crosscast cases. The differences between those are only important in the case of multiple inheritance and/or non-public inheritance. In either of these cases, type must be a type of some subobject of the full object of e.

The primer never says whether it means static or dynamic type of e, but in either case the description is completely wrong. For the cast to succeed,

  • type does not need to be related to the static type of e in any way
  • type must be a base class of the dynamic type of e or that type itself (but not a proper derived class of it), with further restrictions related to accessibility and non-ambiguity.


来源:https://stackoverflow.com/questions/49381515/is-the-c-primer-making-something-wrong-with-the-usage-of-dynamic-cast

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!