![]() |
Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология Образование Политология Производство Психология Стандартизация Технологии |
Эта программа генерирует такие результаты.
Объект 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; Просмотров: 654; Нарушение авторского права страницы