dynamic_cast + virtual methods
От: pasenger  
Дата: 04.02.04 14:04
Оценка:
почему при вызове виртуального метода базового класса после dynamic_cast вызывается exception?

#include "stdio.h"

class A
{
public:
    void doIt() { printf("A::doIt()\n"); }
    virtual doItVirtual() { printf("A::doItVirtual()\n"); }
    virtual ~A() {};
};

class B : public A
{
public:
    void doIt() { printf("B::doIt()\n"); }
    virtual ~B() {};
};

void main()
{
    B *pB, *pB1;
    pB = new B();
    pB->doIt();         // B::doIt()
    pB->doItVirtual();  // A::doItVirtual()
    delete(pB);

    A a;
    pB1 = dynamic_cast<B*>(&a);
    pB1->doIt();        // B::doIt()
    pB1->doItVirtual(); // VC7(System.NullReferenceException) VC6(Access Violation)
}
Re: dynamic_cast + virtual methods
От: Lorenzo_LAMAS  
Дата: 04.02.04 14:06
Оценка:
потому что dynamic_cast базы А к производному В вернет 0.
Of course, the code must be complete enough to compile and link.
Re: dynamic_cast + virtual methods
От: jazzer Россия Skype: enerjazzer
Дата: 04.02.04 14:15
Оценка: +1
Здравствуйте, pasenger, Вы писали:


P>почему при вызове виртуального метода базового класса после dynamic_cast вызывается exception?


потому что так задуман dynamic_cast
в случае, если ты осуществляешь невалидное преобразование (а именно это ты и делаешь), dynamic_cast вернет тебе 0, а ты это должен проверить. Он затем и придуман, чтобы проверять и сообщать, если что не так.

А если ты будешь кастить не указатели, а ссылки, но dynamic_cast сам кинется в тебя исключением std::bad_cast.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[2]: dynamic_cast + virtual methods
От: pasenger  
Дата: 04.02.04 14:16
Оценка:
Здравствуйте, Lorenzo_LAMAS, Вы писали:

L_L>потому что dynamic_cast базы А к производному В вернет 0.


в том-то и дело, что нет! я ж написал (см. 3ю строку)

    A a;
    pB1 = dynamic_cast<B*>(&a);
    pB1->doIt();        // !!!!!!! B::doIt()
    pB1->doItVirtual(); // VC7(System.NullReferenceException) VC6(Access Violation)
Re[3]: dynamic_cast + virtual methods
От: Lorenzo_LAMAS  
Дата: 04.02.04 14:27
Оценка:
doIt — невиртуальная, так ее вызывать нельзя с нулевым указателем (неопределенное поведение), но ты, нарушая правила вызвал и тебе "повезло", кстати, попробуй в ней что-нибудь кому-нибудь присвоить.

Следующая функция — виртуальная, чтоб ее вызвать нужна втбл, указатель на которую д.б. в объекте и тут тебе уже не "повезло" — у тебя нулевой указатель.
Of course, the code must be complete enough to compile and link.
Re[4]: dynamic_cast + virtual methods
От: Lorenzo_LAMAS  
Дата: 04.02.04 14:28
Оценка:
Попробуй, например, такое.
class A
{
public:
    virtual ~A(){}
    void fun()
    {
        i_ = 0;
    }
private:
    int i_;
};

class B:public A
{
};

int main()
{
    A a;
    B * pb = dynamic_cast<B *>(&a);
    pb->fun();
    
    return 0;
}
Of course, the code must be complete enough to compile and link.
Re[4]: dynamic_cast + virtual methods
От: pasenger  
Дата: 04.02.04 14:46
Оценка:
Здравствуйте, Lorenzo_LAMAS, Вы писали:

L_L>doIt — невиртуальная, так ее вызывать нельзя с нулевым указателем (неопределенное поведение), но ты, нарушая правила вызвал и тебе "повезло", кстати, попробуй в ней что-нибудь кому-нибудь присвоить.


вот-те раз... действительно нулл... this = 0x00000000 как же так?.. а почему неопределенное поведение? и как это она зовет метод от нулевого указателя? объясните пожалуйста
Re[5]: dynamic_cast + virtual methods
От: Lorenzo_LAMAS  
Дата: 04.02.04 14:52
Оценка:
P>вот-те раз... действительно нулл... this = 0x00000000 как же так?..

Объект типа А объектом типа В не является, поэтому при попытке такого преобразования dynamic_cast вернет 0 для случая указателя, либо бросит std::bad_cast для случая ссылок(как уже сказад jazzer)

P>а почему неопределенное поведение? и как это она зовет метод от нулевого указателя? объясните пожалуйста


Потому что такой вызов аналогичен (*p).doIt() — разыменование нулевого указателя. "Работает" т.к. doIt — обычная функция, которой в качестве невидимого тебе параметра передается 0 (this).
//pseudo-code, not C++
//p->doIt();
doIt(p);
Of course, the code must be complete enough to compile and link.
Re[5]: dynamic_cast + virtual methods
От: jazzer Россия Skype: enerjazzer
Дата: 04.02.04 14:53
Оценка: +2 :))
Здравствуйте, pasenger, Вы писали:

P>Здравствуйте, Lorenzo_LAMAS, Вы писали:


L_L>>doIt — невиртуальная, так ее вызывать нельзя с нулевым указателем (неопределенное поведение), но ты, нарушая правила вызвал и тебе "повезло", кстати, попробуй в ней что-нибудь кому-нибудь присвоить.


P>вот-те раз... действительно нулл... this = 0x00000000 :wow: как же так?..

см. мой предыдущий ответ
P>а почему неопределенное поведение?
по определению. Разыменование нулевого указателя — оно самое и есть.
P>и как это она зовет метод от нулевого указателя?
как умеет, так и зовет
обычно форматирует винчестер, но сегодня тебе повезло
P>объясните пожалуйста
воспользуйся поиском, тыщу раз уже все это обсуждалось
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[6]: dynamic_cast + virtual methods
От: Vamp Россия  
Дата: 04.02.04 15:12
Оценка: :))
J>обычно форматирует винчестер, но сегодня тебе повезло
Нихьт. Обычно она посылает матерные письма начальнику, а исходный код системы — конкурентам.
Да здравствует мыло душистое и веревка пушистая.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.