Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- Используется RTTI (Runtime Type Information), чтобы привести один указатель на объект класса к другому указателю на объект класса. Классы должны быть полиморфными, то есть в базовом классе должна быть хотя бы одна виртуальная функция. Если эти условие не соблюдено, ошибка возникнет на этапе компиляции.
- и
- Если есть класс A и класс B, который наследуется от A, то что правильнее использовать, чтобы привести B к A? Вроде и static_cast и dynamic_cast работают корректно.
- Ошибкой компиляции dynamic_cast будет неудачная попытка приведения вниз (от базового к наследнику) по не-полиморфной иерархии классов: даже если приведение производится корректно.
- Если приводить вверх по иерархии классов то всё работает ок.
- RTTI для dynamic_cast "включается" только для полиморфных классов. RTTI здесь значит что приведение типов происходит во время выполнения, результат приведения соотвественно известен тоже во время выполнения.
- (Ходят слухи что в некоторых реализациях dynamic_cast берет информацию о типах из таблицы виртуальных функций, куда компилятор может также запихнуть указатель на инфу об иерархии классов во время генерации кода:
- http://stackoverflow.com/a/18359906/2170898)
- Пример:
- class X
- {
- virtual ~X() {} // виртуальный деструктор
- };
- class Y : public class X // иерархия X - Y полифорфная, так как в X определен виртуальный деструктор
- {};
- При вызове new X в свободной памяти будет создан экземпляр класса X.
- Графически это можно изобразить так (первая строка - номера ячеек памяти, вторая строка - объект который лежит по указанному адресу):
- [100001] [100002] [100003]
- [..X...] [.junk.] [.junk.]
- Вызов new Y сначала создает и размещает в памяти объект класса X, а следом за ним объект класса Y.
- [200001] [200002] [200003]
- [..X...] [..Y...] [.junk.]
- Если приводить указатель на базовый класс X к указателю на класс наследника Y, когда в памяти нет объекта типа Y, то dynamic_cast вернет nullptr:
- X * ptr_X = new X; // [....X....] [..junk...] [..junk...]
- Y * ptr_Y = dynamic_cast<Y *>(ptr_X); // ptr_Y будет проиницилизирован nullptr
- Что вполне логично, так как в памяти нет никакого объекта типа Y, к которому можно было бы обратится - в памяти находится какой-то мусор, который не получается идентифицировать как объект типа Y.
- Если то же самое сделать для неполиморфной иерархии классов SuperBase и Derived:
- class SuperBase
- {};
- class Derived : public class SuperBase
- {};
- То получим ошибку компиляции:
- SuperBase * ptr_SuperBase = new SuperBase; // объекты в памяти: (SuperBase)|(junk)|(junk)
- Derived * ptr_Derived = dynamic_cast<Derived *>(ptr_SuperBase); // error C2683: 'dynamic_cast': 'SuperBase' is not a polymorphic type
- Даже если сделать приведение вниз по иерархии "корректным":
- SuperBase * ptr_SuperBase = new Derived; // объекты в памяти: (SuperBase)|(Derived)|(junk)
- Derived * ptr_Derived = dynamic_cast<Derived *>(ptr_SuperBase); // error C2683: 'dynamic_cast': 'SuperBase' is not a polymorphic type
- Для ссылок ошибка будет такая же:
- SuperBase obj_SuperBase;
- Derived & ref_Derived = dynamic_cast<Derived &>(obj_SuperBase); // error C2683: 'dynamic_cast': 'SuperBase' is not a polymorphic type
- Приведение вверх по иерархии будет произведено успешно и для ссылок и для указателей:
- Derived obj_Derived;
- SuperBase & ref_SuperBase = dynamic_cast<SuperBase &>(obj_Derived); // ok
- Derived * ptr_Derived = new Derived;
- SuperBase * ptr_SuperBase = dynamic_cast<SuperBase * >(ptr_Derived); // ok
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement