странное поведение при использовании dynamic_cast [duplicate]

0

Я наткнулся на какое-то странное поведение, экспериментируя с dynamic_cast. Это код, который я имею

struct Base
{
    virtual ~Base(){}    
    virtual void output() = 0;
};

struct Derived1 : public Base
{
    void output() {}    
    void doDerived_1()
    {
        std::cout << "derived 1\n";
    }
};

struct Derived2: public Base
{ 
    void output() {}
    void doDerived_2()
    {
        std::cout << "derived 2\n";
    }
};     

int main()
{
    Base* base = new Derived1();
    Derived2* der2 = dynamic_cast<Derived2*>(base);
    // der2 = 0
    der2->doDerived_2();
}

Хотя der2 равно 0, doDerived_2() все равно будет вызываться, и любой код внутри него будет выполнен. Кодекс ломается, когда я вызываю функцию output().

Может кто-нибудь объяснить мне, почему это работает и не ломается, когда это ясно? благодаря

  • 3
    Неопределенное поведение. Но вы должны проверить, если приведение успешно, прежде чем использовать результат.
  • 0
    Неопределенное поведение разыменовывать nullptr !
Показать ещё 6 комментариев
Теги:
dynamic-cast

2 ответа

3
Лучший ответ

Ваш код имеет неопределенное поведение, потому что вы разыскиваете нулевой указатель.

Тем не менее, возможная реализация для вызова функции-члена осуществляется через соглашение вызова thiscall, которое неявно передает указатель объекта в качестве первого параметра. Если ваша функция не имеет доступа к каким-либо переменным-членам, this указатель не разыменован, и функция может выполняться так, как ожидалось. Это не имеет ничего общего с dynamic_cast.

Обратите внимание, что это не гарантируется в стандарте

Пример:

struct Foo {
    int doIt() {return 42;}
};

int main() {
    Foo *f = NULL;
    std::cout << f->doIt();
}

Печать 42 на некоторых компиляторах

2

Вы разыскиваете нулевой указатель. Поведение такой операции не определено. В этом случае происходит вызов метода, при this он является нулевым указателем. Однако все может случиться.

Если вы хотите, чтобы исключение было выбрано вместо этого, введите ссылки:

Derived2& der2 = dynamic_cast<Derived2&>(*base);
der2.doDerived_2();

В качестве альтернативы вы можете использовать if-statement для выполнения некоторого кода только в том случае, если листинг преуспевает:

if (Derived2* der2 = dynamic_cast<Derived2*>(base)) {
    der2->doDerived_2();
}
  • 0
    Я знаю, что должен проверить правильность указателя перед вызовом любого из методов-членов. Меня просто смутило, что когда указатель равен 0, он все еще работает. Пример @king_nak послужил хорошим объяснением такого поведения.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню