dynamic_cast和static_cast [英] dynamic_cast and static_cast in C++

查看:154
本文介绍了dynamic_cast和static_cast的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对C ++中的 dynamic_cast 关键字感到困惑。

  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,因为'a'不是'B'
B * b2 = dynamic_cast< B *> (ap); //'b'
C * c = dynamic_cast< C *> (ap); // 空值。

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

定义说:


dynamic_cast 关键字从一个指针或引用
类型转换一个基准,运行时检查以确保转换的有效性


我们可以写一个等效的 dynamic_cast

code> ;> dynamic_cast<> ,因为它们属于指针。这只是一个101级的下降,它不覆盖所有的复杂性。



static_cast<类型*>(ptr)



这需要 ptr 中的指针,并尝试将其安全地转换为指针类型键入* 。这个转换在编译时完成。如果类型类型是相关的,它将只执行转换。如果类型不相关,你会得到一个编译错误。例如:

  class B {}; 
class D:public B {};
class X {};

int main()
{
D * d = new D;
B * b = static_cast< B *>(d); // this works
X * x = static_cast< X *>(d); //错误 - 不会编译
return 0;
}



dynamic_cast<类型*>(ptr)



这再次尝试接受 ptr 中的指针并将其安全地转换为指针类型* 。但是这个转换在运行时执行,而不是编译时。因为这是一个运行时强制转换,所以它特别适合与多态类结合使用。事实上,在证书案件中,为了使演员合法,类必须是多态的。



演员可以沿着两个方向:从碱基到衍生物(B2D)或从衍生物到碱基(D2B)。它很简单,看看D2B cast如何在运行时工作。 ptr 源自类型或它不是。在D2B dynamic_cast的情况下,规则是简单的。您可以尝试将任何内容转换为其他任何内容,如果 ptr 实际上是从类型派生的, a dynamic_cast 返回指针。否则,你会得到一个NULL指针。



但是B2D转换有点复杂。考虑下面的代码:

  #include< iostream> 
using namespace std;

class Base
{
public:
virtual void DoIt()= 0; // pure virtual
virtual〜Base(){};
};

class Foo:public Base
{
public:
virtual void DoIt(){cout< Foo; };
void FooIt(){cout< Fooing It ...; }
};

class Bar:public Base
{
public:
virtual void DoIt(){cout< 酒吧; }
void BarIt(){cout<< baring It ...; }
};

Base * CreateRandom()
{
if((rand()%2)== 0)
return new Foo;
else
return new Bar;
}


int main()
{
for(int n = 0; n <10; ++ n)
{
Base * base = CreateRandom();

base-> DoIt();

Bar * bar =(Bar *)base;
bar-> BarIt();
}
return 0;
}

main()不能告诉什么类型的对象 CreateRandom()将返回,所以C风格的转换 Bar * bar =(Bar *)base; / code>决定不是类型安全。你怎么能解决这个问题?一种方法是向基类中添加一个函数bool AreYouABar()const = 0; 并返回 true Bar false Foo 。但还有另一种方法:使用 dynamic_cast<>

  main()
{
for(int n = 0; n <10; ++ n)
{
Base * base = CreateRandom

base-> DoIt();

Bar * bar = dynamic_cast< Bar *>(base);
Foo * foo = dynamic_cast< Foo *>(base);
if(bar)
bar-> BarIt();
if(foo)
foo-> FooIt();
}
return 0;

}

casts在运行时执行,通过查询对象(现在不需要担心如何),询问它是否是我们正在寻找的类型。如果是, dynamic_cast< Type *> 返回一个指针;



为了使用 dynamic_cast<> ,Base,Foo和Bar必须是标准调用的多态类型 。为了成为一个多态类型,你的类必须至少有一个 virtual 函数。如果您的类不是多态类型,则 dynamic_cast 的基础派生用法将无法编译。示例:

  class Base {}; 
class Der:public Base {};


int main()
{
Base * base = new Der;
Der * der = dynamic_cast< Der *>(base); //错误 - 不会编译

return 0;
}

向base添加一个虚函数,例如虚拟dtor, Base和Der多态类型:

  class Base 
{
public:
virtual〜Base (){};
};
class Der:public Base {};


int main()
{
Base * base = new Der;
Der * der = dynamic_cast< Der *>(base); // OK

return 0;
}


I am quite confused with the dynamic_cast keyword in 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
}

the definition says:

The dynamic_cast keyword casts a datum from one pointer or reference type to another, performing a runtime check to ensure the validity of the cast

Can we write an equivalent of dynamic_cast of C++ in C so that I could better understand things?

解决方案

Here's a rundown on static_cast<> and dynamic_cast<> specifically as they pertain to pointers. This is just a 101-level rundown, it does not cover all the intricacies.

static_cast< Type* >(ptr)

This takes the pointer in ptr and tries to safely cast it to a pointer of type Type*. This cast is done at compile time. It will only perform the cast if the type types are related. If the types are not related, you will get a compiler error. For example:

class B {};
class D : public B {};
class X {};

int main()
{
  D* d = new D;
  B* b = static_cast<B*>(d); // this works
  X* x = static_cast<X*>(d); // ERROR - Won't compile
  return 0;
}

dynamic_cast< Type* >(ptr)

This again tries to take the pointer in ptr and safely cast it to a pointer of type Type*. But this cast is executed at runtime, not compile time. Because this is a run-time cast, it is useful especially when combined with polymorphic classes. In fact, in certian cases the classes must be polymorphic in order for the cast to be legal.

Casts can go in one of two directions: from base to derived (B2D) or from derived to base (D2B). It's simple enough to see how D2B casts would work at runtime. Either ptr was derived from Type or it wasn't. In the case of D2B dynamic_cast<>s, the rules are simple. You can try to cast anything to anything else, and if ptr was in fact derived from Type, you'll get a Type* pointer back from dynamic_cast. Otherwise, you'll get a NULL pointer.

But B2D casts are a little more complicated. Consider the following code:

#include <iostream>
using namespace std;

class Base
{
public:
    virtual void DoIt() = 0;    // pure virtual
    virtual ~Base() {};
};

class Foo : public Base
{
public:
    virtual void DoIt() { cout << "Foo"; }; 
    void FooIt() { cout << "Fooing It..."; }
};

class Bar : public Base
{
public :
    virtual void DoIt() { cout << "Bar"; }
    void BarIt() { cout << "baring It..."; }
};

Base* CreateRandom()
{
    if( (rand()%2) == 0 )
        return new Foo;
    else
        return new Bar;
}


int main()
{
    for( int n = 0; n < 10; ++n )
    {
        Base* base = CreateRandom();

            base->DoIt();

        Bar* bar = (Bar*)base;
        bar->BarIt();
    }
  return 0;
}

main() can't tell what kind of object CreateRandom() will return, so the C-style cast Bar* bar = (Bar*)base; is decidedly not type-safe. How could you fix this? One way would be to add a function like bool AreYouABar() const = 0; to the base class and return true from Bar and false from Foo. But there is another way: use dynamic_cast<>:

int main()
{
    for( int n = 0; n < 10; ++n )
    {
        Base* base = CreateRandom();

        base->DoIt();

        Bar* bar = dynamic_cast<Bar*>(base);
        Foo* foo = dynamic_cast<Foo*>(base);
        if( bar )
            bar->BarIt();
        if( foo )
            foo->FooIt();
    }
  return 0;

}

The casts execute at runtime, and work by querying the object (no need to worry about how for now), asking it if it the type we're looking for. If it is, dynamic_cast<Type*> returns a pointer; otherwise it returns NULL.

In order for this base-to-derived casting to work using dynamic_cast<>, Base, Foo and Bar must be what the Standard calls polymorphic types. In order to be a polymorphic type, your class must have at least one virtual function. If your classes are not polymorphic types, the base-to-derived use of dynamic_cast will not compile. Example:

class Base {};
class Der : public Base {};


int main()
{
    Base* base = new Der;
    Der* der = dynamic_cast<Der*>(base); // ERROR - Won't compile

    return 0;
}

Adding a virtual function to base, such as a virtual dtor, will make both Base and Der polymorphic types:

class Base 
{
public:
    virtual ~Base(){};
};
class Der : public Base {};


int main()
{
    Base* base = new Der;
    Der* der = dynamic_cast<Der*>(base); // OK

    return 0;
}

这篇关于dynamic_cast和static_cast的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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