|
Программирование >> Разработка устойчивых систем
linclude <typeinfo> using namespace std: class Bl { public: virtual -BIO {} class B2 { public: virtual -820 {} class MI : public Bl. public 82 {}: class Mi2 : public MI {}: int mainO { B2* b2 - new Mi 2: Mi 2* mi 2 - dynamic cast<Mi2*>(b2); MI* mi - dynamic cast<MI*>(b2): Bl* bl = dynamic~cast<Bl*>(b2); assert(typeid(b2) !- typeid(Mi2*)): assert(typeid(b2) typeid(B2*)): delete b2: } III- В этом примере возникают дополнительные трудности, связанные с множественным наследованием (эта тема рассматривается далее в настоящей главе, а также в главе 9). Если создать объект Mi2 и преобразовать его к корневому типу (в данном случае выбирается один из двух возможных корней), то приведение к любому из производных уровней Ml или Mi2 через dynamic cast оказывается успешным. Возможно даже преобразование от одного корня к другому: В1* Ы = dynamic cast<Bl*>(b2): Такое преобразование проходит успешно, потому что В2 в действительности ссылается на объект Mi2, который содержит подобъект типа В1. Преобразование к промежуточным типам открывает интересное различие между операторами dynamic cast и typeid. Оператор typeid всегда выдает указатель на статический объект typejnfo, описывающий динамический тип объекта. Таким образом, он не предоставляет информации о промежуточных уровнях. В следующем (истинном) выражении оператор typeid, в отличие от dynamic cast, не воспринимает Ь2 как указатель на производный тип: typeid(Ь2) != typeid(Mi2*) Тип Ь2 просто соответствует фактическому типу указателя: typeid(Ь2) != typeid(В2*) Указатели на void RTTI работает только с полноценными типами. Иначе говоря, при использовании оператора typeid должна быть доступна вся информация о классе. В частности, RTTI не работает с указателями на void: : C08:Vo1dRTTI.cpp RTTI и указатели на void Вызов dynamic cast<void*> всегда дает адрес всего объекта (не одного из его подобъектов). Эта тема более подробно рассматривается в следующей главе. !#include <iostream> linclude <typeinfo> using namespace std: class Stimpy { public: virtual void happyО {} virtual void joyO {} virtual -StimpyО {} int mainO { void* V - new Stimpy: Ошибка: ! Stimpy* s - dynamic cast<Stimpy*>(v): Ошибка: ! cout typeid(*v).nameO endl. } III- Синтаксис void* фактически означает информация о типе отсутствует . RTTI и шаблоны RTTI нормально работает с шаблонами классов, поскольку они просто генерируют новые классы. В частности, RTTI позволяет легко определить имя текущего класса. Следующая программа выводит сообщения о вызове конструкторов и деструкторов: : C08:Constructor0rder.cpp Порядок вызовов конструкторов linclude <iostream> linclude <typeinfo> using namespace std: tempiate<int id> class Announce { public: AnnounceO { cout typeid(*this).nameO constructor endl: -AnnounceO { cout typeid(*this).name() destructor endl: class X : public Announce<0> { Announce<l> ml: Announce<2> m2: public: XO { cout X::X() endl: } ~X() { cout X::-X() endl: } int mainO { X x: } /:- class Bl class B2 class MI virtual public BB {}: virtual public BB {}: public Bl. public B2 {}: int mainO { BB* bbp = new MI: Upcast Правильное определение имени: cout typeid(*bbp).name() endl: Dynamic cast работает правильно: MI* mip = dynamic cast<MI*>(bbp): Принудительное преобразование типа в старом стиле невозможно: ! Ml* mip2 = (MI*)bbp: Ошибка компиляции } III:- Оператор typeid правильно определяет имя для фактического объекта даже через указатель на виртуальный базовый класс. Оператор dynamic cast тоже работает правильно. Тем не менее, компилятор не позволяет выполнить принудительное преобразование типа старым способом: Ml* mip2 = (MI*)bbp: Ошибка компиляции В данном случае шаблон параметризуется по константам int, но подошли бы и типовые аргументы. Внутри конструктора и деструктора мы средствами RTTI определяем имя класса для вывода. В классе X используется наследование и композиция, чтобы порядок вызова конструкторов и деструкторов был нетривиальным. Результат выглядит так: Announce<0> constructor Announce<l> constructor Announce<2> constructor X::X() X::~X() Announce<2> destructor Announce<l> destructor Announce<0> destructor Естественно, конкретный вывод зависит от того, как ваш компилятор представляет результат вызова name(). Множественное наследование Механизм RTTI должен правильно работать со всеми сложными аспектами множественного наследования, включая виртуальные базовые классы (эта тема подробно рассматривается в следующей главе; возможно, вам стоит вернуться к этому разделу после прочтения главы 9). : С08:RTTIandMultiplelnheritance.cpp #i nclude <iostream> #i nclude <typeinfo> using namespace std: class BB { public: virtual void fO {} virtual ~BB() {}
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |