我dynamic_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, 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关键字将数据从一种指针或引用类型转换为另一种,执行运行时检查以确保转换的有效性
我们可以在 C 中编写相当于dynamic_castC++ 的内容,以便我更好地理解事物吗?
这是一个关于指针的概要static_cast<>,dynamic_cast<>特别是它们与指针有关的内容。这只是一个101级的纲要,并没有涵盖所有的错综复杂。
static_cast<>
dynamic_cast<>
这会将指针放入ptr并尝试将其安全地转换为 type 的指针Type*。这个转换是在编译时完成的。 如果类型相关 ,它只会执行强制转换。如果类型不相关,您将收到编译器错误。例如:
ptr
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; }
这再次尝试获取指针ptr并将其安全地转换为 type 的指针Type*。但是这个转换是在运行时执行的,而不是编译时。因为这是一个运行时强制转换,所以在与多态类结合使用时尤其有用。事实上,在某些情况下,类 必须 是多态的,才能使强制转换合法。
强制转换可以沿两个方向之一进行:从基础到派生 (B2D) 或从派生到基础 (D2B)。看看 D2B 转换如何在运行时工作很简单。要么ptr来自,要么Type不是。对于 D2B dynamic_cast<>s,规则很简单。您可以尝试将任何内容转换为其他任何内容,如果ptr实际上是从 派生的Type,您Type*将从dynamic_cast. 否则,您将得到一个 NULL 指针。
Type
但是 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和falsefrom中返回Foo。但是还有另一种方法:使用dynamic_cast<>:
main()
CreateRandom()
Bar* bar = (Bar*)base;
AreYouABar() const = 0;
true
Bar
false
Foo
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<Type*>
为了使这种从基到派生的转换能够使用dynamic_cast<>,Base、Foo 和 Bar 必须是标准所称的 多态类型 。为了成为多态类型,您的类必须至少具有一个virtual函数。如果您的类不是多态类型,则从基到派生的使用dynamic_cast将无法编译。例子:
virtual
class Base {}; class Der : public Base {}; int main() { Base* base = new Der; Der* der = dynamic_cast<Der*>(base); // ERROR - Won't compile return 0; }
将虚函数添加到 base 中,例如 virtual 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; }