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

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

Страниц: [1]   Вниз
  Печать  
Автор Тема: Перекрестное преобразование. Dynamic_cast.  (Прочитано 7695 раз)
Pupil
Гость
« : Сентябрь 30, 2014, 09:45 »

При изучении примера Перекрестного преобразования типа между производными классами одного базового класса из книги Павловской том 1 написано, что
Цитировать
Классы С и D являются производными от класса В. Функции demo передается указатель
на класс D, являющийся на самом деле указателем на «братский» для него
класс С, поэтому динамическое преобразование типа из D в С в функции demo завершается
успешно.

У меня функция demo выдает false, т.е. неудачу кастования.

Вопрос: Сбой на этапе неявного преобразования типа С в тип D при передаче в функцию demo или Кастомщик не может тип С преобразовать в D?

Код:
#include <QtCore/QCoreApplication>
#include <iostream>
#include <typeinfo>
class B{
    public: virtual void f1(){};
};
class C: public B{
    public: void f2(){ std::cout << "f2 is true"; };
};
class D: public B{
    public: void f3(){ std::cout << "f3 is true"; };
};
void demo(D* p){
    C* c = dynamic_cast<C*>(p); // Кастомщик понимает, что ему дали объект типа C?
    if(c) {c->f2(); std::cout << "it executed" << std::endl;}
    else {std::cout << std::endl << " it isn't executed ";} // Не выполнено
    }


int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    B* b = new C;  // Объявляем переменную типа C.
    demo((D*)b);   // передаем ее в функцию, принимающую указатель на тип D

    //D* c = static_cast<D*>(b);
    //std::cout<< typeid(*c).name() << std::endl;
    //demo((D*)c);

    return a.exec();
}

Или данный вид преобразования невозможен как написано в http://www.cplusplus.com/doc/tutorial/typecasting/,
т.е. конвертации классовые конвертации только от базового к дочернему и обратно?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #1 : Сентябрь 30, 2014, 10:19 »

Нет, не только к родителю и обратно, "бегать по веткам" (кросс-приведение)  должно работать. Проверьте включено ли RTTI в опциях компилятора.

[/off]
Код:
    if(c) {c->f2(); std::cout << "it executed" << std::endl;}
    else {std::cout << std::endl << " it isn't executed ";} // Не выполнено
}
Конечно Вы имеете право на свой стиль, но воспринимается тяжело. Лучше напр так
Код
C++ (Qt)
   if (c) {
      c->f2();
      std::cout << "it executed" << std::endl;
   }
   else
      std::cout << std::endl << " it isn't executed "; // Не выполнено
 
Записан
Pupil
Гость
« Ответ #2 : Сентябрь 30, 2014, 10:51 »

Igors, при проверке включен или выключен RTTI командой
Цитировать
typeid
. Она срабатывает.
Верно ли в таком случае, что rtti ключен?

В файле pro добавил:
Код:
CONFIG   += rtti

Результат не изменился.
Записан
Swa
Самовар
**
Offline Offline

Сообщений: 170


Просмотр профиля
« Ответ #3 : Сентябрь 30, 2014, 11:31 »

Специально нашёл эту книгу и главу из которой вы взяли пример и скорее всего в книге ошибка.

Оператор dynamic_cast может осуществлять преобразование из базового в дочерний класс или наоборот, но не может преобразовывать "братские" классы потому что они не находятся в одной иерархии.

Однако это преобразование можно сделать используя приведение в стиле С:
Код:
(D*)b
тут происходит простое преобразование типа, а dynamic_cast перед преобразованием проверяет, находятся ли оба класса в одной цепочке наследования.

Почитайте вот эту тему, там тоже обсуждают ваш пример.

Вообще, выбросите эту книгу. Читайте Прату или Страуструпа. На худой конец Шилдта.
Записан
OKTA
Гость
« Ответ #4 : Сентябрь 30, 2014, 12:08 »

А не вот это имелось ввиду под перекрестным преобразованием?

Код
C++ (Qt)
class B{
public:
   virtual void f1(){
       //
 
       qDebug() << "B";
   }
};
class C {
public:
   virtual void f2(){
       //
 
       qDebug() << "C";
   }
};
class D: public B, public C {};
 
void demo(B* b) {
   //
 
   C* c = dynamic_cast<C*>(b);
   if(c)
       c->f2();
}
 
int main(int argc, char *argv[]) {
   //
 
   QCoreApplication a(argc, argv);
 
   D* d = new D;
   demo(d);
   delete d;
 
   return a.exec();
}
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #5 : Сентябрь 30, 2014, 12:40 »

Оператор dynamic_cast может осуществлять преобразование из базового в дочерний класс или наоборот, но не может преобразовывать "братские" классы потому что они не находятся в одной иерархии.
Только что проверил пример на icc 12.1 - успешно приводит. А вот MSVC 2012 нет. Зависит от компилятора

Однако это преобразование можно сделать используя приведение в стиле С:
Код:
(D*)b
тут происходит простое преобразование типа, а dynamic_cast перед преобразованием проверяет, находятся ли оба класса в одной цепочке наследования.
Это выглядит как static_cast, т.к. можно проверить и на компиляции. И не постесняюсь спросить: а какое "простое"? Т.е. в чем оно заключается?

А не вот это имелось ввиду под перекрестным преобразованием?
Код
C++ (Qt)
   D* d = new D;
}
Ну так точно C * не получить т.к. создавался D

А если более практично, то вот так сработает всегда и везде
Код
C++ (Qt)
B * b = dynamic_cast <B *> (p);
C * c = dynamic_cast <C *> (b);
Записан
OKTA
Гость
« Ответ #6 : Сентябрь 30, 2014, 12:46 »

Получить получить, D ведь и B и C в себе содержит.
Записан
Pupil
Гость
« Ответ #7 : Сентябрь 30, 2014, 12:47 »

Igors, D->B->C. Верно?
Записан
Swa
Самовар
**
Offline Offline

Сообщений: 170


Просмотр профиля
« Ответ #8 : Сентябрь 30, 2014, 12:58 »

Только что проверил пример на icc 12.1 - успешно приводит. А вот MSVC 2012 нет. Зависит от компилятора
Первый раз такое слышу.
Даже Алёна говорит, что так нельзя делать.

И не постесняюсь спросить: а какое "простое"? Т.е. в чем оно заключается?
Имелось в виду без проверки типов, которую делает dynamic_cast
Записан
OKTA
Гость
« Ответ #9 : Сентябрь 30, 2014, 13:04 »

А если более практично, то вот так сработает всегда и везде
Код
C++ (Qt)
B * b = dynamic_cast <B *> (p);
C * c = dynamic_cast <C *> (b);

Так тоже не будет работать для первоначального примера.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #10 : Сентябрь 30, 2014, 15:18 »

Получить получить, D ведь и B и C в себе содержит.
Виноват, не увидел множественного наследования (и за что его ругают?). Да, так приводит даже MSVC - остальное можно не проверять.

Первый раз такое слышу.
Даже Алёна говорит, что так нельзя делать.
Тоже мне бабский авторитет Улыбающийся Но ведь в примере OKTA "С" не является ни потомком ни родителем "B" - но приводится. Помню неск лет назад была почти такая же тема - и у меня "вбок" работало

А если более практично, то вот так сработает всегда и везде
Код
C++ (Qt)
B * b = dynamic_cast <B *> (p);
C * c = dynamic_cast <C *> (b);

Так тоже не будет работать для первоначального примера.
Проверил на 3 компиляторах, везде работает. Да и нет оснований чтобы не работало, т.к. static_cast проходит для обоих

Igors, D->B->C. Верно?
Да.
Записан
OKTA
Гость
« Ответ #11 : Сентябрь 30, 2014, 15:32 »

Igors, покажи код, который проверял на трех компиляторах. На mingw у меня отказывается работать.
Записан
Pupil
Гость
« Ответ #12 : Сентябрь 30, 2014, 15:41 »

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

Сообщений: 11445


Просмотр профиля
« Ответ #13 : Октябрь 05, 2014, 10:37 »

Igors, покажи код, который проверял на трех компиляторах. На mingw у меня отказывается работать.
Код
C++ (Qt)
#include <iostream>
#include <typeinfo>
 
class B {
   public: virtual void f1(){};
};
 
class C: public B{
   public: void f2(){ std::cout << "f2 is true"; };
};
 
class D: public B {
   public: void f3(){ std::cout << "f3 is true"; };
};
 
void demo( D * p )
{
//    C * c = dynamic_cast <C *> (p);
   B * b = dynamic_cast <B *> (p);
   C * c = dynamic_cast <C *> (b);
   if (c) {
c->f2();
std::cout << "it executed" << std::endl;
}
   else
std::cout << std::endl << " it isn't executed "; // Не выполнено
}
 
int main(int argc, char *argv[])
{
   B * b = new C;  
   demo((D*) b);  
   return 0;
}
Проверял на gcc 4.2, icc 12.1 и MSVC 2012
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


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