dynamic_cast和static_cast [英] dynamic_cast and static_cast in C++
问题描述
我对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 $ c $
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 从
指针。否则,你会得到一个NULL指针。 dynamic_cast
返回
但是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屋!