Ось пробіг на static_cast<>
таdynamic_cast<>
конкретно, коли вони стосуються покажчиків. Це просто 101 рівень рівня, він не охоплює всіх тонкощів.
static_cast <Тип *> (ptr)
Це забирає вказівник 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)
Це знову намагається взяти вказівник ptr
і безпечно віддати його до вказівника типу 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()
повернеться, тому актерський стиль у Bar* bar = (Bar*)base;
форматі C , очевидно, не є безпечним для типу. Як ви могли це виправити? Одним із способів було б додати таку функцію, як bool, AreYouABar() const = 0;
до базового класу та повернутись true
із Bar
та false
з Foo
. Але є й інший спосіб: 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;
}
Касти виконуються під час виконання та працюють, запитуючи об’єкт (не потрібно турбуватися про те, як зараз), запитуючи його, чи це той тип, який ми шукаємо. Якщо він є, dynamic_cast<Type*>
повертає вказівник; в іншому випадку він повертає NULL.
Щоб цей кастинг з базовим походженням працював 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); // 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 ++ працює), гарною книгою (що також досить легко читати для чогось такого технічного) є "Внутрішня об'єктна модель C ++" Ліппмена. Також книги "Структура та еволюція C ++" та "Мова програмування на C ++" Струструпа є хорошими ресурсами, але книга Ліппмана присвячена тому, як C ++ працює "за кадром".