Russian Qt Forum
Ноябрь 23, 2024, 23:05 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: 1 [2]   Вниз
  Печать  
Автор Тема: dynamic_cast и просто приведение - в чем разница?  (Прочитано 11646 раз)
zenden
Гость
« Ответ #15 : Ноябрь 28, 2010, 12:37 »

Авварон
приведите, пожалуйста, работающий код
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #16 : Ноябрь 28, 2010, 12:59 »

zenden
Я не тестил, но по идее что-то типа:
Код:
class Base
{
}
class IFace1
{
    virtual int f() {}
}
class IFace2
{
    virtual int g() {}
}
class Derived : public Base, IFace1, IFace2
{
    virtual int f() {}
    virtual int g() {}
}
void h()
{
   Base *o = new Derived;
   IFace1 *o1 = (IFace1*)o; // ok, vtable совпадают, тк у Base нет вирт ф-ий
   IFace2 *o2 = (IFace2*)o; // fail, мы читаем vtable 1го класса, а должны 2го
}

Происходит так потому что, скорее всего, указатель на vtable один, а втейблы от 2х классов просто склеиваются. При динамик касте оффсет на 2й втейбл считается адекватно, а при сишном не считается вообще.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #17 : Ноябрь 28, 2010, 16:36 »

Напоролись на что-то - выкладывайте сразу ответ. А то я 5 минут плевался о том что "делать мне больше нечего" и 1 минуту думал вам решение.
Ну я ж предупредил - вопрос для начинающих. А от сразу выложенного ответа немного толку - все так много знают ... Улыбающийся

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

Код
C++ (Qt)
  Derived *o = new Derived;  // вмещающий класс
  IFace1 *o1 =  dynamiс_cast <IFace1*> (o);  // здесь С приведение имеет тот же эффект
  IFace2 *o2 =  dynamiс_cast <IFace2*> (o);  // здесь тоже
  ...
  IFace1 *o3 =  dynamiс_cast <IFace1*> (o2);  // а здесь С приведение даст неверный результат
}
Последнее приведение и было на что я напоролся. Все тоже самое можно и с Base * (вместо Derived *) если Base имеет virtual(ы).

Как я понял, dynamiс_cast умеет как-то "запрыгнуть" на "полную" VMT (с каким типом объект создавался) и оттуда уже смотреть. Замечание: (мой) отладчик показывает приведенные указатели одинаковые, но это не так если их напечатать. "С" приведение также меняет указатель, но не всегда удачно  Улыбающийся
Записан
spectre71
Гость
« Ответ #18 : Ноябрь 28, 2010, 19:18 »

zenden
Я не тестил, но по идее что-то типа:
Код:
class Base
{
}
class IFace1
{
    virtual int f() {}
}
class IFace2
{
    virtual int g() {}
}
class Derived : public Base, IFace1, IFace2
{
    virtual int f() {}
    virtual int g() {}
}
void h()
{
   Base *o = new Derived;
   IFace1 *o1 = (IFace1*)o; // ok, vtable совпадают, тк у Base нет вирт ф-ий
   IFace2 *o2 = (IFace2*)o; // fail, мы читаем vtable 1го класса, а должны 2го
}

Происходит так потому что, скорее всего, указатель на vtable один, а втейблы от 2х классов просто склеиваются. При динамик касте оффсет на 2й втейбл считается адекватно, а при сишном не считается вообще.

Все в данном примере нормально. Никаких  fail не может быть.

Извиняюсь. Не ообратил внимание на:
Base *o = new Derived;

Но это не потому что у Base нет виртуальных функций, а потому что  Base  не связана наследованием с IFace1  и IFace2.

А вот так все нормально:
Код
C++ (Qt)
void h()
{
  Derived*o = new Derived;
  Base*b = (Base*)o;
  IFace1 *o1 = (IFace1*)o;
  IFace2 *o2 = (IFace2*)o;
}
« Последнее редактирование: Ноябрь 28, 2010, 19:39 от Spectre » Записан
spectre71
Гость
« Ответ #19 : Ноябрь 28, 2010, 19:22 »

Как я понял, dynamiс_cast умеет как-то "запрыгнуть" на "полную" VMT (с каким типом объект создавался) и оттуда уже смотреть. Замечание: (мой) отладчик показывает приведенные указатели одинаковые, но это не так если их напечатать. "С" приведение также меняет указатель, но не всегда удачно  Улыбающийся


Это просто ошибка!
IFace1 *o3 =  dynamiс_cast <IFace1*> (o2);
Пытаемся приводить IFace2 к IFace1. Какой в этом смысл? Они не связаны отношением наследования.


Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #20 : Ноябрь 28, 2010, 19:42 »

Все в данном примере нормально. Никаких  fail не может быть.
Ну не надо так придираться к мелочам - идея совершенно правильная  Улыбающийся Рухнет если Base будет иметь хотя бы 1 член данных. Если же Base будет иметь virtual - то имеем тяжелые ошибки на выполнении. А без virtual компилятор не позволит написать dynamic_cast<Base *>

Это просто ошибка!
IFace1 *o3 =  dynamiс_cast <IFace1*> (o2);
Пытаемся приводить IFace2 к IFace1. Какой в этом смысл? Они не связаны отношением наследования.
Не связаны. Но если оба базовые классы, то можно перескочить с o1 на o2 и обратно через dynamic_cast (этого я не знал  Улыбающийся). И получить указатель на наследующий класс (Derived *) тоже можно.
Записан
spectre71
Гость
« Ответ #21 : Ноябрь 28, 2010, 19:53 »

Не связаны. Но если оба базовые классы, то можно перескочить с o1 на o2 и обратно через dynamic_cast (этого я не знал  Улыбающийся). И получить указатель на наследующий класс (Derived *) тоже можно.

А зачем так делать? Что за модель данных этого может потребовать?

Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #22 : Ноябрь 28, 2010, 20:01 »

А вот так все нормально:
Код
C++ (Qt)
void h()
{
  Derived*o = new Derived;
  Base*b = (Base*)o;
  IFace1 *o1 = (IFace1*)o;
  IFace2 *o2 = (IFace2*)o;
}
Не поверите, тут даже касты не нужны)))
Записан
spectre71
Гость
« Ответ #23 : Ноябрь 28, 2010, 20:08 »

А вот так все нормально:
Код
C++ (Qt)
void h()
{
  Derived*o = new Derived;
  Base*b = (Base*)o;
  IFace1 *o1 = (IFace1*)o;
  IFace2 *o2 = (IFace2*)o;
}
Не поверите, тут даже касты не нужны)))

Согласен!

Но в приведенном вами примере и dynamic_cast не поможет - Base не виртуальный. А вот если сделать его виртуальным, то да:
dynamic_cast - работает
() - не работает

Однако никакого смысла прыгать по веткам не вижу!

« Последнее редактирование: Ноябрь 28, 2010, 20:17 от Spectre » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #24 : Ноябрь 28, 2010, 20:46 »

Но в приведенном вами примере и dynamic_cast не поможет - Base не виртуальный. А вот если сделать его виртуальным, то да:
dynamic_cast - работает
() - не работает
Да, но речь идет о таком коде (полагаем что Base виртуальный)
Код
C++ (Qt)
  Base * b = new Derived();
  IFace1 *o1 = (IFace1*) b;
  IFace2 *o2 = (IFace2*) b;
}
Это будет работать корректно с dynamic_cast, но не без него

Однако никакого смысла прыгать по веткам не вижу!
Да я тоже не видел, но пришлось  Улыбающийся Эквивалентно 2 dynamic_cast - взять вмещающий класс и от него
нужный базовый
Записан
Страниц: 1 [2]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.246 секунд. Запросов: 22.