C ++中的dynamic_cast和static_cast

C ++中的dynamic_cast和static_cast

dynamic_cast对C ++中的关键字很困惑。

struct A {
    virtual void f() { }};struct B : public A { };struct C { };void f () {
    A a;
    B b;

    A* ap = &b;
    B* b1 = dynamic_cast<B*> (&a);  // NULL, because 'a' is not a 'B'
    B* b2 = dynamic_cast<B*> (ap);  // 'b'
    C* c = dynamic_cast<C*> (ap);   // NULL.

    A& ar = dynamic_cast<A&> (*ap); // Ok.
    B& br = dynamic_cast<B&> (*ap); // Ok.
    C& cr = dynamic_cast<C&> (*ap); // std::bad_cast}

定义说:

dynamic_cast关键字从一个指针或引用类型到另一个蒙上了基准,执行运行时检查以确保铸造的有效性

我们可以dynamic_cast在C中编写一个等效的C ++,以便我能更好地理解事物吗?


喵喵时光机
浏览 493回答 3
3回答

慕标5832272

这是一个简介static_cast<>,dynamic_cast<>特别是它们与指针有关。这只是一个101级的破旧,它并没有涵盖所有错综复杂的内容。static_cast <Type *>(ptr)这ptr会将指针接入并尝试将其安全地转换为类型的指针Type*。这个演员表是在编译时完成的。如果类型类型相关,它将仅执行强制转换。如果类型不相关,则会出现编译器错误。例如:class&nbsp;B&nbsp;{};class&nbsp;D&nbsp;:&nbsp;public&nbsp;B&nbsp;{};class&nbsp;X&nbsp;{};int&nbsp;main(){ &nbsp;&nbsp;D*&nbsp;d&nbsp;=&nbsp;new&nbsp;D; &nbsp;&nbsp;B*&nbsp;b&nbsp;=&nbsp;static_cast<B*>(d);&nbsp;//&nbsp;this&nbsp;works &nbsp;&nbsp;X*&nbsp;x&nbsp;=&nbsp;static_cast<X*>(d);&nbsp;//&nbsp;ERROR&nbsp;-&nbsp;Won't&nbsp;compile &nbsp;&nbsp;return&nbsp;0;}dynamic_cast <Type *>(ptr)这再次尝试将指针插入ptr并安全地将其转换为类型的指针Type*。但是这个演员表是在运行时执行的,而不是编译时。因为这是一个运行时转换,所以特别是在与多态类组合时非常有用。实际上,在certian情况下,类必须是多态的,以使转换合法。演员可以进入两个方向之一:从基础到派生(B2D)或从派生到基础(D2B)。这很简单,可以看到D2B强制转换如何在运行时运行。要么ptr是源于,Type要么不是。在D2B dynamic_cast <> s的情况下,规则很简单。您可以尝试将任何内容转换为其他内容,如果ptr实际上是派生出来的Type,那么您将获得一个Type*指针dynamic_cast。否则,您将获得一个NULL指针。但是B2D演员阵容有点复杂。请考虑以下代码:#include&nbsp;<iostream>using&nbsp;namespace&nbsp;std;class&nbsp;Base{public: &nbsp;&nbsp;&nbsp;&nbsp;virtual&nbsp;void&nbsp;DoIt()&nbsp;=&nbsp;0;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;pure&nbsp;virtual &nbsp;&nbsp;&nbsp;&nbsp;virtual&nbsp;~Base()&nbsp;{};};class&nbsp;Foo&nbsp;:&nbsp;public&nbsp;Base{public: &nbsp;&nbsp;&nbsp;&nbsp;virtual&nbsp;void&nbsp;DoIt()&nbsp;{&nbsp;cout&nbsp;<<&nbsp;"Foo";&nbsp;};&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;FooIt()&nbsp;{&nbsp;cout&nbsp;<<&nbsp;"Fooing&nbsp;It...";&nbsp;}};class&nbsp;Bar&nbsp;:&nbsp;public&nbsp;Base{public&nbsp;: &nbsp;&nbsp;&nbsp;&nbsp;virtual&nbsp;void&nbsp;DoIt()&nbsp;{&nbsp;cout&nbsp;<<&nbsp;"Bar";&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;BarIt()&nbsp;{&nbsp;cout&nbsp;<<&nbsp;"baring&nbsp;It...";&nbsp;}};Base*&nbsp;CreateRandom(){ &nbsp;&nbsp;&nbsp;&nbsp;if(&nbsp;(rand()%2)&nbsp;==&nbsp;0&nbsp;) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;new&nbsp;Foo; &nbsp;&nbsp;&nbsp;&nbsp;else &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;new&nbsp;Bar;}int&nbsp;main(){ &nbsp;&nbsp;&nbsp;&nbsp;for(&nbsp;int&nbsp;n&nbsp;=&nbsp;0;&nbsp;n&nbsp;<&nbsp;10;&nbsp;++n&nbsp;) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Base*&nbsp;base&nbsp;=&nbsp;CreateRandom(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;base->DoIt(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Bar*&nbsp;bar&nbsp;=&nbsp;(Bar*)base; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bar->BarIt(); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;return&nbsp;0;}main()不知道什么样的对象CreateRandom()会返回,所以C风格的演员Bar* bar = (Bar*)base;阵容绝对不是类型安全的。你怎么能解决这个问题?一种方式是像布尔函数添加AreYouABar() const = 0;到基类,并返回true从Bar和false从Foo。但还有另一种方法:使用dynamic_cast<>:int&nbsp;main(){ &nbsp;&nbsp;&nbsp;&nbsp;for(&nbsp;int&nbsp;n&nbsp;=&nbsp;0;&nbsp;n&nbsp;<&nbsp;10;&nbsp;++n&nbsp;) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Base*&nbsp;base&nbsp;=&nbsp;CreateRandom(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;base->DoIt(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Bar*&nbsp;bar&nbsp;=&nbsp;dynamic_cast<Bar*>(base); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Foo*&nbsp;foo&nbsp;=&nbsp;dynamic_cast<Foo*>(base); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(&nbsp;bar&nbsp;) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bar->BarIt(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(&nbsp;foo&nbsp;) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;foo->FooIt(); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;return&nbsp;0;}强制转换在运行时执行,并通过查询对象来工作(无需担心现在如何),询问它是否是我们正在寻找的类型。如果是,则dynamic_cast<Type*>返回指针;&nbsp;否则返回NULL。为了使这个基础到派生的转换能够使用dynamic_cast<>,Base,Foo和Bar必须是Standard所谓的多态类型。要成为多态类型,您的类必须至少具有一个virtual函数。如果您的类不是多态类型,dynamic_cast则不会编译从基础到派生的使用。例:class&nbsp;Base&nbsp;{};class&nbsp;Der&nbsp;:&nbsp;public&nbsp;Base&nbsp;{};int&nbsp;main(){ &nbsp;&nbsp;&nbsp;&nbsp;Base*&nbsp;base&nbsp;=&nbsp;new&nbsp;Der; &nbsp;&nbsp;&nbsp;&nbsp;Der*&nbsp;der&nbsp;=&nbsp;dynamic_cast<Der*>(base);&nbsp;//&nbsp;ERROR&nbsp;-&nbsp;Won't&nbsp;compile &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;0;}向基础添加虚拟功能(例如虚拟dtor)将同时生成Base和Der多态类型:class&nbsp;Base&nbsp;{public: &nbsp;&nbsp;&nbsp;&nbsp;virtual&nbsp;~Base(){};};class&nbsp;Der&nbsp;:&nbsp;public&nbsp;Base&nbsp;{};int&nbsp;main(){ &nbsp;&nbsp;&nbsp;&nbsp;Base*&nbsp;base&nbsp;=&nbsp;new&nbsp;Der; &nbsp;&nbsp;&nbsp;&nbsp;Der*&nbsp;der&nbsp;=&nbsp;dynamic_cast<Der*>(base);&nbsp;//&nbsp;OK &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;0;}

侃侃无极

除非您实现自己的手动RTTI(并绕过系统),否则无法dynamic_cast直接在C ++用户级代码中实现。dynamic_cast与C ++实现的RTTI系统密切相关。但是,为了帮助您理解RTTI(以及dynamic_cast更多),您应该阅读<typeinfo>标题和typeid操作符。这将返回与您手头的对象相对应的类型信息,您可以从这些类型的信息对象中查询各种(有限的)事物。

桃花长相依

不仅仅是C中的代码,我认为英语定义就足够了:给定一个类Base,它有一个派生类Derived,dynamic_cast当且仅当指向的实际对象实际上是Derived对象时,才会将Base指针转换为Derived指针。class&nbsp;Base&nbsp;{&nbsp;virtual&nbsp;~Base()&nbsp;{}&nbsp;};class&nbsp;Derived&nbsp;:&nbsp;public&nbsp;Base&nbsp;{};class&nbsp;Derived2&nbsp;:&nbsp;public&nbsp;Base&nbsp;{};class&nbsp;ReDerived&nbsp;:&nbsp;public&nbsp;Derived&nbsp;{};void&nbsp;test(&nbsp;Base&nbsp;&&nbsp;base&nbsp;){ &nbsp;&nbsp;&nbsp;dynamic_cast<Derived&>(base);}int&nbsp;main()&nbsp;{ &nbsp;&nbsp;&nbsp;Base&nbsp;b; &nbsp;&nbsp;&nbsp;Derived&nbsp;d; &nbsp;&nbsp;&nbsp;Derived2&nbsp;d2; &nbsp;&nbsp;&nbsp;ReDerived&nbsp;rd; &nbsp;&nbsp;&nbsp;test(&nbsp;b&nbsp;);&nbsp;&nbsp;&nbsp;//&nbsp;throw:&nbsp;b&nbsp;is&nbsp;not&nbsp;a&nbsp;Derived&nbsp;object &nbsp;&nbsp;&nbsp;test(&nbsp;d&nbsp;);&nbsp;&nbsp;&nbsp;//&nbsp;ok &nbsp;&nbsp;&nbsp;test(&nbsp;d2&nbsp;);&nbsp;&nbsp;//&nbsp;throw:&nbsp;d2&nbsp;is&nbsp;not&nbsp;a&nbsp;Derived&nbsp;object &nbsp;&nbsp;&nbsp;test(&nbsp;rd&nbsp;);&nbsp;&nbsp;//&nbsp;ok:&nbsp;rd&nbsp;is&nbsp;a&nbsp;ReDerived,&nbsp;and&nbsp;thus&nbsp;a&nbsp;derived&nbsp;object}在示例中,调用test将不同的对象绑定到引用Base。在内部,参考downcasted的引用Derived类型安全方式:丧气将只对那些情况下,被引用的对象确实是一个实例成功Derived。
打开App,查看更多内容
随时随地看视频慕课网APP