Пример реального мира dynamic_cast в С++
Может ли кто-нибудь дать мне реальный пример того случая, когда требуется динамическое_сканирование и вообще не может быть сработано? Примеры, о которых я могу думать, обычно можно обрабатывать с двойной отправкой.
Если ограничение слишком велико, пример, когда dynamic_cast, как правило, подходит, также будет приятным.
Я бы хотел увидеть реальные примеры вместо "обычно используется для переноса между типами вверх и вниз по дереву типов".
Ответы
Ответ 1
Двойная отправка требует, чтобы типы, которые взаимодействуют, имеют интимные знания друг о друге, так как это требует, чтобы один класс вызывал методы другого класса. dynamic_cast
работает, если вы не можете изменить внутренности класса или не хотите нарушать инкапсуляцию рассматриваемых классов.
То есть, двойная отправка является инвазивной для соответствующих классов, а dynamic_cast
работает без знания приведения в классы.
Вы также можете использовать dynamic_cast
, если вы не знаете перегрузку целевого метода, которая будет вызвана. Например, см. этот вопрос, который я опубликовал вчера.
Наконец, двойная отправка не приходит без головных болей
Базовый класс Shape должен знать обо всех производных классах, что приводит к циклическим зависимостям. Если вы вывели новый класс из Shape (например, Triangle), вы должны обновить интерфейс Shape и интерфейс/реализацию всех других производных классов. В некоторых случаях это даже не вариант: у вас может не быть исходного кода для Shape или он не хочет или не разрешает его изменять.
Ответ 2
Ограничение "вообще не работает" слишком велико. Любая функция С++ может быть эмулирована в C. Все, что вам нужно сделать, чтобы обойти эту функцию, так сказать, - использовать этот код на С++. Например, MFC, библиотека, созданная с глубины времени до стандартизации языка 1998 года, предложила и по-прежнему предлагает свой собственный динамический состав.
Одним из примеров, когда вам обычно требуется динамическое кастинг, является шаблон посетителя, например. как используется для обработки событий. Идея посещения заключается в централизации динамического кастинга, так что вместо динамических бросков, заполненных во всем коде, есть один:
#include <stdio.h>
void say( char const s[] ) { printf( "%s\n", s ); }
struct Event
{
struct Handler
{
virtual void onEvent( Event& ) = 0;
};
virtual void dispatchTo( Handler& aHandler )
{
aHandler.onEvent( *this );
}
template< class SpecificEvent >
static void dispatch( SpecificEvent& e, Handler& aHandler )
{
typedef typename SpecificEvent::Handler SpecificHandler;
// The single dynamic cast:
if( SpecificHandler* p = dynamic_cast<SpecificHandler*>( &aHandler ) )
{
p->onEvent( e );
}
else
{
e.Event::dispatchTo( aHandler );
}
}
};
struct FooEvent
: Event
{
struct Handler
{
virtual void onEvent( FooEvent& ) = 0;
};
virtual void dispatchTo( Event::Handler& aHandler )
{
dispatch( *this, aHandler );
}
};
struct Plane
: Event::Handler
{
virtual void onEvent( Event& ) { say( "An event!" ); }
};
struct Fighter
: Plane
, FooEvent::Handler // Comment out this line to get "An event!".
{
virtual void onEvent( FooEvent& ) { say( "Foo Fighter!" ); }
};
void doThingsTo( Plane& aPlane )
{
FooEvent().dispatchTo( aPlane );
}
int main()
{
Fighter plane;
doThingsTo( plane );
}
Вывод этой программы Foo Fighter!
.
Как уже упоминалось, это упрощается. Реальность имеет тенденцию быть немного более грязной. И с гораздо большим количеством кода.
Приветствия и hth.
Ответ 3
Я лично использую его для работы через определенные части моего игрового движка. У меня есть базовый класс сущностей, из которого я получаю различные другие объекты. Я передал их базовому классу, чтобы я мог легко хранить их в связанном списке. Когда я хочу проверить, не является ли какая-то конкретная запись в моем списке определенной сущностью, я dynamic_cast это для этого типа. Если он возвращает null, то я этого не знаю.
Ответ 4
Скажем, у нас есть библиотека, которую мы используем, которая предназначена для того, чтобы мы выводили некоторые типы из:
class A {};
class B : public A {};
class C : public B {};
И когда мы выводим наши типы, у нас есть некоторые вещи, общие для всех наших случаев:
class CommonStuff {};
class D : public CommonStuff, public C {};
Теперь, когда мы работаем с нашей библиотекой, и есть обратный вызов, который принимает тип A & (или B & или C &)
void some_func(A& obj);
И предположим, что в этой функции он ожидает полиморфного поведения, но нам нужно получить доступ к некоторым нашим CommonStuff:
void some_func(A& obj)
{
CommonStuff& comn = dynamic_cast<CommonStuff&>(obj);
}
Поскольку нет прямой корреляции между A и CommonStuff, мы не можем использовать static_cast
, reinterpret_cast
, очевидно, не правильный выбор, так как он будет вводить срез. Единственный вариант - dyanmic_cast
.
Теперь, возьмите это с солью, потому что это можно обойти.
Ответ 5
Вы можете часто заменять dynamic_cast < A * > (...) путем добавления виртуальной функции к A. Однако, если A является классом из сторонней библиотеки, вы не можете изменить его, чтобы вы не могли добавьте к нему виртуальную функцию. Поэтому вам, возможно, придется использовать dynamic_cast.