Advertisement
Cynacyn

dynamic_cast compilation failure for non-polymorphic classes

May 10th, 2016
91
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 5.08 KB | None | 0 0
  1. Используется RTTI (Runtime Type Information), чтобы привести один указатель на объект класса к другому указателю на объект класса. Классы должны быть полиморфными, то есть в базовом классе должна быть хотя бы одна виртуальная функция. Если эти условие не соблюдено, ошибка возникнет на этапе компиляции.
  2.  
  3. и
  4.  
  5. Если есть класс A и класс B, который наследуется от A, то что правильнее использовать, чтобы привести B к A? Вроде и static_cast и dynamic_cast работают корректно.
  6.  
  7. Ошибкой компиляции dynamic_cast будет неудачная попытка приведения вниз (от базового к наследнику) по не-полиморфной иерархии классов: даже если приведение производится корректно.
  8. Если приводить вверх по иерархии классов то всё работает ок.
  9.  
  10. RTTI для dynamic_cast "включается" только для полиморфных классов. RTTI здесь значит что приведение типов происходит во время выполнения, результат приведения соотвественно известен тоже во время выполнения.
  11. (Ходят слухи что в некоторых реализациях dynamic_cast берет информацию о типах из таблицы виртуальных функций, куда компилятор может также запихнуть указатель на инфу об иерархии классов во время генерации кода:
  12. http://stackoverflow.com/a/18359906/2170898)
  13.  
  14. Пример:
  15.  
  16. class X
  17. {
  18.    virtual ~X() {} // виртуальный деструктор
  19. };
  20.  
  21. class Y : public class X // иерархия X - Y полифорфная, так как в X определен виртуальный деструктор
  22. {};
  23.  
  24.  
  25. При вызове new X в свободной памяти будет создан экземпляр класса X.
  26. Графически это можно изобразить так (первая строка - номера ячеек памяти, вторая строка - объект который лежит по указанному адресу):
  27. [100001] [100002] [100003]
  28. [..X...] [.junk.] [.junk.]
  29.  
  30. Вызов new Y сначала создает и размещает в памяти объект класса X, а следом за ним объект класса Y.
  31. [200001] [200002] [200003]
  32. [..X...] [..Y...] [.junk.]
  33.  
  34. Если приводить указатель на базовый класс X к указателю на класс наследника Y, когда в памяти нет объекта типа Y, то dynamic_cast вернет nullptr:
  35.  
  36. X * ptr_X = new X; // [....X....] [..junk...] [..junk...]
  37. Y * ptr_Y =  dynamic_cast<Y *>(ptr_X); // ptr_Y будет проиницилизирован nullptr
  38.  
  39. Что вполне логично, так как в памяти нет никакого объекта типа Y, к которому можно было бы обратится - в памяти находится какой-то мусор, который не получается идентифицировать как объект типа Y.
  40. Если то же самое сделать для неполиморфной иерархии классов SuperBase и Derived:
  41.  
  42. class SuperBase
  43. {};
  44.  
  45. class Derived : public class SuperBase
  46. {};
  47.  
  48. То получим ошибку компиляции:
  49.  
  50. SuperBase * ptr_SuperBase = new SuperBase; // объекты в памяти: (SuperBase)|(junk)|(junk)
  51. Derived * ptr_Derived =  dynamic_cast<Derived *>(ptr_SuperBase); // error C2683: 'dynamic_cast': 'SuperBase' is not a polymorphic type
  52.  
  53. Даже если сделать приведение вниз по иерархии "корректным":
  54.  
  55. SuperBase * ptr_SuperBase = new Derived; // объекты в памяти: (SuperBase)|(Derived)|(junk)
  56. Derived * ptr_Derived =  dynamic_cast<Derived *>(ptr_SuperBase); // error C2683: 'dynamic_cast': 'SuperBase' is not a polymorphic type
  57.  
  58. Для ссылок ошибка будет такая же:
  59. SuperBase obj_SuperBase;
  60. Derived & ref_Derived = dynamic_cast<Derived &>(obj_SuperBase); // error C2683: 'dynamic_cast': 'SuperBase' is not a polymorphic type
  61.  
  62.  
  63. Приведение вверх по иерархии будет произведено успешно и для ссылок и для указателей:
  64.  
  65. Derived obj_Derived;
  66. SuperBase & ref_SuperBase = dynamic_cast<SuperBase &>(obj_Derived); // ok
  67.  
  68. Derived * ptr_Derived = new Derived;
  69. SuperBase * ptr_SuperBase = dynamic_cast<SuperBase * >(ptr_Derived); // ok
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement