Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология Образование Политология Производство Психология Стандартизация Технологии |
Эта программа генерирует такие результаты.
Объект o1 имеет тип class myclass< int> Объект o2 имеет тип class myclass< int> Объект o3 имеет тип class myclass< double> Объекты o1 и o2 имеют одинаковый тип. Объекты o1 и o3 имеют разные типы. Как видите, несмотря на то, что два объекта являются экземплярами одного и того же шаблонного класса, если их параметризованные данные не совпадают, они не эквивалентны по типу. В этой программе объект o1 имеет тип myclass< int> , а объект o3 — тип myclass< double> . Таким образом, это объекты разного типа. Рассмотрим еще один пример применения оператора typeid к шаблонным классам, а именно модифицированную версию программы определения геометрических фигур из предыдущего раздела. На этот раз класс figure мы сделали шаблонным. // Шаблонная версия figure-иерархии. #include < iostream> #include < cstdlib> using namespace std; template < class T> Class figure { protected: T x, y; public: figure(T i, T j) { x = i; у = j; } virtual T area() = 0; }; template < class T> class triangle: public figure< T> { public: triangle(T i, T j): figure< T> (i, j) {} T area() { return x * 0.5 * y; } }; template < class T> class rectangle: public figure< T> { public: rectangle(T i, T j): figure< T> (i, j) {} T area() { return x * y; } }; template < class T> class circle: public figure< T> { public: circle(T i, T j=0): figure< T> (i, j) {} T area() { return 3.14 * x * x; } }; // Фабрика объектов, генерируемых из класса figure. figure< double> *generator() { switch(rand() % 3 ) { case 0: return new circle< double> (10.0); case 1: return new triangle< double> (10.1, 5.3); case 2: return new rectangle< double> (4.3, 5.7); } return 0; } Int main() { figure< double> *p; int i; int t=0, c=0, r=0; // генерируем и подсчитываем объекты for(i=0; i< 10; i++) { p = generator(); cout < < " Объект имеет тип " < < typeid(*p).name(); cout < < ". "; // учитываем объект if(typeid(*p) == typeid(triangle< double> )) t++; if(typeid(*p) == typeid(rectangle< double> )) r++; if(typeid(*p) == typeid(circle< double> )) c++; cout < < " Площадь равна " < < p-> area() < < endl; } cout < < endl; cout < < " Сгенерированы такие объекты: "; cout < < " треугольников: " < < t < < endl; cout < < " прямоугольников: " < < r < < endl; cout < < " кругов: " < < с < < endl; return 0; } Вот как выглядит возможный результат выполнения этой программы. Объект имеет тип class rectangle< double>. Площадь равна 24.51 Объект имеет тип class rectangle< double>. Площадь равна 24.51 Объект имеет тип class triangle< double>. Площадь равна 26.765 Объект имеет тип class triangle< double>. Площадь равна 26.765 Объект имеет тип class rectangle< double>. Площадь равна 24.51 Объект имеет тип class triangle< double>. Площадь равна 26.765 Объект имеет тип class circle< double>. Площадь равна 314 Объект имеет тип class circle< double>. Площадь равна 314 Объект имеет тип class triangle< double>. Площадь равна 26.765 Объект имеет тип class rectangle< double>. Площадь равна 24.51 Сгенерированы такие объекты: треугольников: 4 прямоугольников: 4 кругов: 2 Динамическая идентификация типов используется не в каждой программе. Но при работе с полиморфными типами это средство позволяет узнать тип объекта, обрабатываемого в любой произвольный момент времени. Операторы приведения типов В C++ определено пять операторов приведения типов. Первый оператор (он описан выше в этой книге), применяемый в обычном (традиционном) стиле, был с самого начала встроен в C++. Остальные четыре (dynamic_cast, const_cast, reinterpret_cast и static_cast) были добавлены в язык всего несколько лет назад. Эти операторы предоставляют дополнительные " рычаги управления" характером выполнения операций приведения типа. Рассмотрим каждый из них в отдельности. Оператор dynamic_cast Оператор dynamic_cast выполняет операцию приведения полиморфных типов во время выполнения программы. Возможно, самым важным из новых операторов является оператор динамического приведения типов dynamic_cast. Во время выполнения программы он проверяет обоснованность предлагаемой операции. Если в момент его вызова заданная операция оказывается недопустимой, приведение типов не производится. Общий формат применения оператора dynamic_cast таков. dynamic_cast< type> (expr) Здесь элемент type означает новый тип, который является целью выполнения этой операции, а элемент expr— выражение, приводимое к этому новому типу. Тип type должен быть представлен указателем или ссылкой, а выражение expr должно приводиться к указателю или ссылке. Таким образом, оператор dynamic_cast можно использовать для преобразования указателя одного типа в указатель другого или ссылки одного типа в ссылку другого. Этот оператор в основном используется для динамического выполнения операций приведения типа среди полиморфных типов. Например, если даны полиморфные классы В и D, причем класс D выведен из класса В, то с помощью оператора dynamic_cast всегда можно преобразовать указатель D* в указатель В*, поскольку указатель на базовый класс всегда можно использовать для указания на объект класса, выведенного из базового. Однако оператор dynamic_cast может преобразовать указатель В* в указатель D* только в том случае, если адресуемым объектом действительно является объект класса D. И, вообще, оператор dynamic_cast будет успешно выполнен только при условии, если разрешено полиморфное приведение типов, т.е. если указатель (или ссылка), приводимый к новому типу, может указывать (или ссылаться) на объект этого нового типа или объект, выведенный из него. В противном случае, т.е. если заданную операцию приведения типов выполнить нельзя, результат действия оператора dynamic_cast оценивается как нулевой, если в этой операции участвуют указатели. (Если же попытка выполнить эту операцию оказалась неудачной при участии в ней ссылок, генерируется исключение типа bad_cast.) Рассмотрим простой пример. Предположим, что класс Base — полиморфный, а класс Derived выведен из класса Base. Base *bp, b_ob; Derived *dp, d_ob; bp = & d_ob; // Указатель на базовый класс указывает на объект класса Derived. dp = dynamic_cast< Derived *> (bp); // Приведение к указателю на производный класс разрешено. if(dp) cout < < " Приведение типа прошло успешно! "; Здесь приведение указателя bp (на базовый класс) к указателю dp (на производный класс) успешно выполняется, поскольку bp действительно указывает на объект класса Derived. Поэтому при выполнении этого фрагмента кода будет выведено сообщение Приведение типа прошло успешно! . Но в следующем фрагменте кода попытка совершить операцию приведения типа будет неудачной, поскольку bp в действительности указывает на объект класса Base, и неправомерно приводить указатель на базовый класс к типу указателя на производный, если адресуемый им объект не является на самом деле объектом производного класса. bp = & b_ob; /* Указатель на базовый класс ссылается на объект класса Base. */ dp = dynamic_cast< Derived *> (bp); // ошибка! if(! dp) cout < < " Приведение типа выполнить не удалось"; Поскольку попытка выполнить операцию приведения типа оказалась неудачной, при выполнении этого фрагмента кода будет выведено сообщение Приведение типа выполнить не удалось. В следующей программе демонстрируются различные ситуации применения оператора dynamic_cast. // Использование оператора dynamic_cast. #include < iostream> using namespace std; class Base { public: virtual void f() { cout < < " В классе Base."; } //... }; class Derived: public Base { public: void f() { cout < < " В классе Derived."; } }; Int main() { Base *bp, b_ob; Derived *dp, d_ob; dp = dynamic_cast< Derived *> (& d_ob); if(dp) { cout < < " Приведение типов " < < " (из Derived * в Derived *) реализовано."; dp-> f(); } else cout < < " Ошибка"; cout < < endl; bp = dynamic_cast< Base *> (& d_ob); if(bp) { cout < < " Приведение типов " < < " (из Derived * в Base *) реализовано."; bp-> f(); } else cout < < " Ошибка"; cout < < endl; bp = dynamic_cast< Base *> (& b_ob); if(bp) { cout < < " Приведение типов " < < " (из Base * в Base *) реализовано."; bp-> f(); } else cout < < " Ошибка"; cout < < endl; dp = dynamic_cast< Derived *> (& b_ob); if(dp) cout < < " Ошибка"; else cout < < " Приведение типов " < < " (из Base * в Derived *) не реализовано."; cout < < endl; bp = & d_ob; // bp указывает на объект класса Derived dp = dynamic_cast< Derived *> (bp); if(dp) { cout < < " Приведение bp к типу Derived *" < < " реализовано, поскольку bp действительно" < < " указывает на объект класса Derived."; dp-> f(); } else cout < < " Ошибка"; cout < < endl; bp = & b_ob; // bр указывает на объект класса Base dp = dynamic_cast< Derived *> (bp); if(dp) cout < < " Ошибка"; else { cout < < " Теперь приведение bp к типу Derived *" < < " не реализовано, поскольку bp" < < " в действительности указывает на объект" < < " класса Base."; } cout < < endl; dp = & d_ob; // dp указывает на объект класса Derived bp = dynamic_cast< Base *> (dp); if(bp) { cout < < " Приведение dp к типу Base * реализовано."; bp-> f(); } else cout < < " Ошибка"; return 0; } Популярное:
|
Последнее изменение этой страницы: 2016-03-17; Просмотров: 1157; Нарушение авторского права страницы