这是一个总结static_cast<>
,dynamic_cast<>
尤其是与指针有关的。这只是一个101级的摘要,并不涵盖所有复杂性。
static_cast <类型*>(ptr)
这ptr
会将指针带入并尝试将其安全地强制转换为type的指针Type*
。此转换在编译时完成。如果类型类型相关,它将仅执行强制类型转换。如果类型不相关,则会出现编译器错误。例如:
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 <类型*>(ptr)
这再次尝试将指针放入ptr
并安全地将其强制转换为type的指针Type*
。但是,此强制转换是在运行时而不是编译时执行的。因为这是运行时强制转换,所以在与多态类结合使用时尤其有用。实际上,在某些情况下,类必须是多态的,才能使转换合法。
强制转换可以沿以下两个方向之一进行:从基础到派生(B2D)或从派生到基础(D2B)。足够简单地了解D2B强制转换在运行时如何工作。要么ptr
源自,Type
要么不是。对于D2B dynamic_cast <> s,规则很简单。您可以尝试将任何内容强制转换为其他任何内容,并且如果ptr
实际上是从派生的Type
,则您将获得的Type*
指针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 << "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()
无法确定CreateRandom()
将返回哪种对象,因此C样式Bar* bar = (Bar*)base;
强制转换绝对不是类型安全的。您该如何解决?一种方法是AreYouABar() const = 0;
在基类中添加bool 之类的函数true
,Bar
然后false
从返回Foo
。但是还有另一种方式:使用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;
}
强制转换在运行时执行,并通过查询对象来工作(现在无需担心),询问它是否是我们要查找的类型。如果是,则dynamic_cast<Type*>
返回一个指针。否则返回NULL。
为了使用这种从基类到源类的转换dynamic_cast<>
,Base,Foo和Bar必须是Standard称为多态类型的类型。为了成为多态类型,您的类必须至少具有一个virtual
函数。如果您的类不是多态类型,则从基到源使用dynamic_cast
则将不会编译。例:
class Base {};
class Der : public Base {};
int main()
{
Base* base = new Der;
Der* der = dynamic_cast<Der*>(base); // ERROR - Won't compile
return 0;
}
向基础添加虚拟函数(例如虚拟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;
}
dynamic_cast<>
幕后的工作方式(或多少C ++的工作方式),那么Lippman的“ Inside the C ++ Object Model”就是一本好书(对于如此技术性的东西也很容易阅读)。同样,Stroustrup的“ C ++的设计和演进”和“ C ++编程语言”这两本书都是不错的资源,但是Lippman的书致力于C ++在幕后的工作方式。