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

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

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: [РЕШЕНО] Использование dynamic-cast  (Прочитано 13668 раз)
Yegor
Гость
« : Май 31, 2017, 21:08 »

Всем здравствуйте!

На счет dynamic_cast. Его используют для того, чтобы преобразовать из указателя на базовый класс в указатель на класс-потомок.

А как на счет преобразования из базового класса на класс-примесь? Который есть дальше в структуре наследования.
Например, есть базовый класс. Он наследуется потомку. А тот потомок еще наследует и класс-примесь.

Можно ли, имея указатель на базовый класс, преобразовать его на класс-примесь? С помощью dynamic_cast.

Спасибо!
« Последнее редактирование: Июнь 02, 2017, 16:16 от Yegor » Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #1 : Май 31, 2017, 21:33 »

Нет, они же в разных иерархиях находятся.
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #2 : Июнь 01, 2017, 07:35 »

У меня это почему-то всегда работало Улыбающийся, но некоторые говорят что нет - ну наверное зависит от реализации. Во всяком случае это всегда можно сделать 2-мя dynamic_cast, так точно приведет
Записан
__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



Просмотр профиля
« Ответ #3 : Июнь 01, 2017, 07:38 »

Разве?
Код
C++ (Qt)
#include <iostream>
 
class Base {
public:
   virtual ~Base() {
 
   }
};
 
class Foo{
public:
   virtual ~Foo() {
 
   }
};
 
class FooBase: public Base, public Foo{    
};
 
int main()
{
   Base *base = new FooBase;
   Foo *foo = dynamic_cast<Foo *>(base);
   if (foo){
       std::cout << "yes";
   }
   else {
       std::cout << "no";
   }
}
 
Компиль имеет дерево наследования и знает как с помощью смещения указателя получить указатель на вторую базу.
Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #4 : Июнь 01, 2017, 09:26 »

Странно, был уверен, что нельзя. Посыпаю голову пеплом.
А стандарт это регламентирует?
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



Просмотр профиля
« Ответ #5 : Июнь 01, 2017, 09:51 »

sidecast, кажется, это называется
Здесь в примере это происходит http://en.cppreference.com/w/cpp/language/dynamic_cast
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #6 : Июнь 01, 2017, 09:59 »

Код
C++ (Qt)
   Foo *foo = dynamic_cast<Foo *>(base);
 
Ну то ясно что приведет, но не о том спрашивалось
Код
C++ (Qt)
#include <stdio.h>
 
struct Root {
virtual ~Root( void ) {}
};
 
struct Leaf1 {
virtual ~Leaf1( void ) {}
};
 
struct Leaf2 {
virtual ~Leaf2( void ) {}
};
 
struct Tree : public Root, public Leaf1, public Leaf2 {
};
 
int main( void )
{
Tree * tree = new Tree;
Leaf1 * leaf1 = tree;
Leaf2 * leaf2 = dynamic_cast<Leaf2 *> (leaf1);
printf("Tree = %p, Leaf1 = %p, Leaf2 = %p\n", tree, leaf1, leaf2);
return 0;
}
Обратите внимание что Leaf1 и Leaf2 не связаны никакими отношениями наследования. Но у меня печатает все 3 адреса разные и ненулевые

А стандарт это регламентирует?
Вроде нет, на усмотрение реализации
Записан
__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



Просмотр профиля
« Ответ #7 : Июнь 01, 2017, 10:32 »

Пример из стандарта:
Код
C++ (Qt)
class A { virtual void f(); };
class B { virtual void g(); };
class D : public virtual A, private B { };
void g() {
   D d;
   B* bp = (B*)&d; // cast needed to break protection
   A* ap = &d; // public derivation, no cast needed
   D& dr = dynamic_cast<D&>(*bp); // fails
   ap = dynamic_cast<A*>(bp); // fails
   bp = dynamic_cast<B*>(ap); // fails
   ap = dynamic_cast<A*>(&d); // succeeds
   bp = dynamic_cast<B*>(&d); // ill-formed (not a run-time check)
}
 
Судя по всему, стандарт предполагает возврат 0 значения указателя при подобных кастах.
Кстати, смутила строка
Код
C++ (Qt)
B* bp = (B*)&d; // cast needed to break protection
А разве здесь правомерно взят адрес B? Кажется тут взят адрес А и преобразован к B.
P.S.: Пантер, к вопросу об отличии reinterpret_cast и pure C cast
Записан
__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



Просмотр профиля
« Ответ #8 : Июнь 01, 2017, 10:53 »

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

Сообщений: 11445


Просмотр профиля
« Ответ #9 : Июнь 01, 2017, 10:57 »

Кстати, смутила строка
Код
C++ (Qt)
B* bp = (B*)&d; // cast needed to break protection
А разве здесь правомерно взят адрес B? Кажется тут взят адрес А и преобразован к B.
Да, bp != &d, С каст автоматом выбирает наилучший вариант приведения, поэтому я всегда считал его "expert mode"  Улыбающийся

Судя по всему, стандарт предполагает возврат 0 значения указателя при подобных кастах.
Хз, в справочнике пример sidecast с классами A. B, D. Повторюсь - у меня это всегда работало, но тут  (уже много лет назад) один паренек проверил мой пример и сказал что нет - ну я ему поверил, выглядел он прилично Улыбающийся

По идее раскрутить все "дерево" можно, т.к. типы идентифицируются, напр для примера выше
Код
C++ (Qt)
Leaf1 * leaf1 = new Leaf1;
Leaf1 * leaf1_1 = tree;
Эти 2 экземпляра имеют один тип но разные VMT, т.е. второй знает что он часть Tree (а не сам по себе)
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #10 : Июнь 01, 2017, 13:01 »

Странно, был уверен, что нельзя. Посыпаю голову пеплом.
А стандарт это регламентирует?

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

Сообщений: 3260


Просмотр профиля
« Ответ #11 : Июнь 01, 2017, 13:12 »

Пример из стандарта:
Код
C++ (Qt)
class A { virtual void f(); };
class B { virtual void g(); };
class D : public virtual A, private B { };
void g() {
   D d;
   B* bp = (B*)&d; // cast needed to break protection
   A* ap = &d; // public derivation, no cast needed
   D& dr = dynamic_cast<D&>(*bp); // fails
   ap = dynamic_cast<A*>(bp); // fails
   bp = dynamic_cast<B*>(ap); // fails
   ap = dynamic_cast<A*>(&d); // succeeds
   bp = dynamic_cast<B*>(&d); // ill-formed (not a run-time check)
}
 
Судя по всему, стандарт предполагает возврат 0 значения указателя при подобных кастах.
Кстати, смутила строка
Код
C++ (Qt)
B* bp = (B*)&d; // cast needed to break protection
А разве здесь правомерно взят адрес B? Кажется тут взят адрес А и преобразован к B.
P.S.: Пантер, к вопросу об отличии reinterpret_cast и pure C cast

Данный пример и не будет работать, потому что
Код:
B* bp1 = (B*)&d;
B* bp2 = &d; // допустим, там public
assert(bp1 == bp2); // false

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

Сообщений: 3260


Просмотр профиля
« Ответ #12 : Июнь 01, 2017, 13:17 »

А не, был не прав. В дебрях виртуального наследования, класс А в  памяти лежит ПОСЛЕ класса B. Тогда непонятно, почему он не видит vtable.
Судя по всему, динамик каст проверяет приватность наследования, других причин не вижу.
« Последнее редактирование: Июнь 01, 2017, 13:18 от Авварон » Записан
__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



Просмотр профиля
« Ответ #13 : Июнь 01, 2017, 13:18 »

Так а что угадывать? Улыбающийся
Я же выше написал, что c++ преобразование в отличии от pure c делает смещение с учётом порядка наследования.
Записан
__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



Просмотр профиля
« Ответ #14 : Июнь 01, 2017, 13:19 »

Виртуальное наследование лежит последним??
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


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