Подтвердить что ты не робот

Пример реального мира dynamic_cast в С++

Может ли кто-нибудь дать мне реальный пример того случая, когда требуется динамическое_сканирование и вообще не может быть сработано? Примеры, о которых я могу думать, обычно можно обрабатывать с двойной отправкой.

Если ограничение слишком велико, пример, когда dynamic_cast, как правило, подходит, также будет приятным.

Я бы хотел увидеть реальные примеры вместо "обычно используется для переноса между типами вверх и вниз по дереву типов".

4b9b3361

Ответ 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.