Что происходит, когда вы используете dynamic_cast между производными классами с одним и тем же базовым классом? - PullRequest
0 голосов
/ 30 мая 2018

Я пытаюсь выяснить, что происходит, когда вы dynamic_cast переходите от одного производного класса к другому производному классу.Почему приведенный ниже код вызывает ошибку сегментации?Обратите внимание, что я не пытаюсь использовать этот код для чего-либо.Я просто хочу понять, что происходит.

Стоит также отметить, что тот же код работает с использованием static_cast.Кажется, я не могу найти какую-либо документацию, в которой подробно описываются происходящие здесь события.Может кто-нибудь объяснить?

struct base 
{ 
    virtual void printing(){cout<<"base printing"<<endl;};
};
struct derived_1 :public base 
{ 
    virtual void printing(){cout<<"derived_1 printing"<<endl;};
};
struct derived_2 :public base 
{ 
    virtual void printing(){cout<<"derived_2 printing"<<endl;};
};

int main()
{
    base * b = new derived_2();
    derived_1 *d_1 = dynamic_cast<derived_1*>(b);

    // calling printing raises segmentation fault
    d_1->printing(); 
}

1 Ответ

0 голосов
/ 30 мая 2018

Приведение к derived_1 завершится неудачей, поскольку derived_2 является объектом base, но не a derived_1.Следовательно, вы не можете выполнить «боковое приведение» к нужному типу указателя.

Не то, что при сбое dynamic_cast возвращается nullptr ( за исключением ссылочных типов ).Это в конечном итоге приводит к ошибке сегментации в вашем коде (в общем, я бы посоветовал вам всегда добавлять if (d_1 != nullptr) перед использованием динамически приводимого объекта).

Обновление:

Кстати, это действительно хороший пример необходимости dynamic_cast.Даже если у вас может возникнуть соблазн использовать static_cast в вашем примере, и он скомпилируется, вы будете иметь дело с неопределенным поведением .Использование static_cast будет компилироваться без всплесков, но на самом деле вы будете работать с неработающим типом.Предположим, derived_1::printing() обращается к некоторой переменной derived_1::a, которой нет в derived_2.При статическом приведении объекта derived_2 (у которого нет a) к derived_1 объекту d_1, вы могли бы ошибочно предположить, что d_1 содержит некоторый действительный a, что не так..

Пример:

// ...
struct derived_1 :public base
{
    const int a = 123;
    void printing() override {cout<<"derived_1 printing " << endl;}
    void foo() { cout << "Foo using constant = " << a << endl; }
};

// ...
int main()
{
    base * b = new derived_2();
    derived_1 *d_1 = static_cast<derived_1*>(b);
    d_1->printing(); // Will call derived_2::printing(), which is not what you expect!
    d_1->foo();      // Won't show a = 123 but some nonesense (mostly 0),
                     // because a is not defined in derived_2.
}
...