2014-09-08 2 views
-3

Пусть код как таковой:dynamic_cast неудачу

#include <iostream> 

using namespace std; 

class dog 
{ 
public: 
    virtual ~dog() 
    { 

    } 
}; 

class yellowdog : public dog 
{ 
    int age; 
    public: 
    void bark() { cout << "woof." << endl;} 
}; 

int main() 
{ 
    dog *pd = new dog(); 
    yellowdog *py = dynamic_cast<yellowdog*>(pd); 
    py->bark(); 
    cout << "py = " << py << endl; 
    cout << "pd = " << pd << endl; 
} 

Выход:

woof. 
py = 0x0 
pd = 0x7fd4d34000e0 

Я понимаю, почему ру = 0. Я знаю, что есть проверка во время выполнения и в этом RUN- проверка времени, есть отказ в преобразовании dog в yellowdog, следовательно, значение py = 0.

Мой вопрос: почему py->bark() все еще может работать. Почему он все еще способен распечатать «woof»?

Приносим извинения за выполненный ранее код. Как проверить сейчас ..

ответ

7

py - нулевой указатель, поэтому py->bark() вызывает неопределенное поведение. Все может случиться, включая вещи, которые, как представляется, работают. В отличие от Java или C#, C++ не гарантирует немедленного сбоя, если вы обращаетесь к нулевому указателю. Во имя эффективности, компиляторы C++, как правило, исключают проверки нулевого указателя.

Как бы то ни было, bark() не использует this, поэтому неудивительно, что все будет хорошо. Вы не должны полагаться на это - нет никакой гарантии, что это сработает, но это не удивительно.

+0

как избежать такого неопределенного поведения? – lakesh

+3

@lakesh _ «как избежать такого неопределенного поведения?» _ Не разыгрывать «nullptr»: P ... –

1

Две причин отливки не удается:

  1. Вы литье указателя типа, не указатель, а затем назначить это указатель. Это должно привести к ошибкам компилятора.

  2. pd является указателем на dog и не yellowdog, поэтому не удручен не возможно, и py будет нулевой указатель (и разыменования это приводит к undefined behavior).

НЕГО неопределенное поведение от второй точки, которая дает вам неприятности. Неопределенное поведение по самому своему определению неопределено, и все может случиться. От сбоев, до вещей , казалось бы, работающих, к внешнему виду nasal demons.

+0

@lakesh Первой проблемой принято заботился, теперь это только вторая проблема. –

0

Это действительно не работает: вызов метода из нулевого указателя является неопределенным поведением. Компилятор может решить, сбой программы, если она работает, если метод не использует члены данных (что и происходит в вашем случае), удалите все данные на вашем диске или даже вызовите команды SWAT у себя дома. Вам повезло, что в вашем случае ничего плохого не происходит.

+0

@lakesh же материал применяется, я не понял, что код был неправильным в первую очередь. – pqnet

0

Что вы сделали в неопределенном поведении, но вы хотите знать, почему это так или иначе работает в вашем случае.

Причина в том, что функция yellowdog::bark() не использует this в любом случае, плюс тот факт, что она встроена в заголовок, означает, что компилятор вполне мог бы просто вставить свою реализацию для вас.

Другими словами, он видит, что вы называли bark() на yellowdog указатель и знает, как осуществить это, он заменяет вызов с cout << "woof." << endl