Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология Образование Политология Производство Психология Стандартизация Технологии |
Программа генерирует такие результаты.
Приведение типов (из Derived* в Derived*) реализовано. В классе Derived. Приведение типов (из Derived* в Base*) реализовано. В классе Derived. Приведение типов (из Base* в Base*) реализовано. В классе Base. Приведение типов (из Base* в Derived*) не реализовано. Приведение bр к типу Derived* реализовано, поскольку bр действительно указывает на объект класса Derived. В классе Derived. Теперь приведение bр к типу Derived* не реализовано, поскольку bр в действительности указывает на объект класса Base. Приведение dp к типу Base * реализовано. В классе Derived. Оператор dynamic_cast можно иногда использовать вместо оператора typeid. Например, предположим, что класс Base — полиморфный и является базовым для класса Derived, тогда при выполнении следующего фрагмента кода указателю dp будет присвоен адрес объекта, адресуемого указателем bp, но только в том случае, если этот объект действительно является объектом класса Derived. Base *bp; Derived *dp; //... if(typeid(*bp) == typeid(Derived)) dp = (Derived *) bp; В этом случае используется обычная операция приведения типов. Здесь это вполне безопасно, поскольку инструкция if проверяет законность операции приведения типов с помощью оператора typeid до ее реального выполнения. То же самое можно сделать более эффективно, заменив операторы typeid и инструкцию if оператором dynamic_cast: dp = dynamic_cast< Derived *> (bp); Поскольку оператор dynamic_cast успешно выполняется только в том случае, если объект, подвергаемый операции приведения к типу, уже является объектом либо заданного типа, либо типа, выведенного из заданного, то после завершения этой инструкции указатель dp будет содержать либо нулевое значение, либо указатель на объект типа Derived. Кроме того, поскольку оператор dynamic_cast успешно выполняется только в том случае, если заданная операция приведения типов законна, то в определенных ситуациях ее логику можно упростить. В следующей программе показано, как оператор typeid можно заменить оператором dynamic_cast. Здесь выполняется один и тот же набор операций дважды: с использованием сначала оператора typeid, а затем оператора dynamic_cast. /* Использование оператора dynamic_cast вместо оператора typeid. */ #include < iostream> #include < typeinfo> using namespace std; class Base { public: virtual void f() {} }; class Derived: public Base { public: void derivedOnly() { cout < < " Это объект класса Derived."; } }; Int main() { Base *bp, b_ob; Derived *dp, d_ob; //-------------------------------- // Использование оператора typeid //-------------------------------- bp = & b_ob; if(typeid(*bp) == typeid(Derived)) { dp = (Derived *) bp; dp-> derivedOnly(); } else cout < < " Операция приведения объекта типа Base к " < < " типу Derived не выполнилась."; bp = & d_ob; if(typeid(*bp) == typeid(Derived)) { dp = (Derived *) bp; dp-> derivedOnly(); } else cout < < " Ошибка, приведение типа должно " < < " быть реализовано! "; //-------------------------------------- // Использование оператора dynamic_cast //-------------------------------------- bp = & b_ob; dp = dynamic_cast< Derived *> (bp); if(dp) dp-> derivedOnly(); else cout < < " Операция приведения объекта типа Base к " < < " типу Derived не выполнилась."; bp = & d_ob; dp = dynamic_cast< Derived *> (bp); if(dp) dp-> derivedOnly(); else cout < < " Ошибка, приведение типа должно " < < " быть реализовано! "; return 0; } Как видите, использование оператора dynamic_cast упрощает логику, необходимую для преобразования указателя на базовый класс в указатель на производный класс. Вот как выглядят результаты выполнения этой программы. Операция приведения объекта типа Base к типу Derived не выполнилась. Это объект класса Derived. Операция приведения объекта типа Base к типу Derived не выполнилась. Это объект класса Derived. И еще. Оператор dynamic_cast можно также использовать применительно к шаблонным классам. Оператор const_cast Оператор const_cast переопределяет модификаторы const и/или volatile. Оператор const_cast используется для явного переопределения модификаторов const и/или volatile. Новый тип должен совпадать с исходным, за исключением его атрибутов const или volatile. Чаще всего оператор const_cast используется для удаления признака постоянства (атрибута const). Его общий формат имеет следующий вид. const_cast< type> (expr) Здесь элемент type задает новый тип операции приведения, а элемент expr означает выражение, которое приводится к новому типу. Использование оператора const_cast демонстрируется в следующей программе. // Демонстрация использования оператора const_cast. #include < iostream> using namespace std; void f (const int *p) { int *v; // Переопределение const-атрибута. v = const_cast< int *> (p); *v = 100; // теперь объект можно модифицировать } Int main() { int x = 99; cout < < " Значение x до вызова функции f(): " < < x< < endl; f (& x); cout < < " Значение x после вызова функции f(): " < < x< < endl; return 0; } Результаты выполнения этой программы таковы. Значение х до вызова функции f(): 99 Значение х после функции f(): 100 Как видите, переменная x была модифицирована функцией f(), хотя параметр, принимаемый ею, задается как const-указатель. Необходимо подчеркнуть, что использование оператора const_cast для удаления const-атрибута является потенциально опасным средством. Поэтому обращайтесь с ним очень осторожно. И еще. Удалять const-атрибут способен только оператор const_cast. Другими словами, ни dynamic_cast, ни static_cast, ни reinterpret_cast нельзя использовать для изменения const-атрибута объекта. Оператор static_cast Оператор static_cast выполняет операцию неполиморфного приведения типов. Оператор static_cast выполняет операцию неполиморфного приведения типов. Его можно использовать для любого стандартного преобразования. При этом во время работы программы никаких проверок на допустимость не выполняется. Оператор static_cast имеет следующий общий формат записи. static_cast< type> (expr) Здесь элемент type задает новый тип операции приведения, а элемент expr означает выражение, которое приводится к этому новому типу. Оператор static_cast, по сути, является заменителем оригинального оператора приведения типов. Он лишь выполняет неполиморфное преобразование. Например, при выполнении следующей программы переменная типа float приводится к типу int. // Использование оператора static_cast. #include < iostream> using namespace std; Int main() { int i; float f; f = 199.22F; i = static_cast< int> (f); cout < < i; return 0; } Оператор reinterpret_cast Оператор reinterpret_cast выполняет фундаментальное изменение типа. Оператор reinterpret_cast преобразует один тип в принципиально другой. Например, его можно использовать для преобразования указателя в целое значение и целого значения — в указатель. Его также можно использовать для приведения наследственно несовместимых типов указателей. Этот оператор имеет следующий общий формат записи. reinterpret_cast< type> (expr) Здесь элемент type задает новый тип операции приведения, а элемент expr означает выражение, которое приводится к этому новому типу. Использование оператора reinterpret_cast демонстрируется в следующей программе. // Пример использования оператора reinterpret_cast. #include < iostream> using namespace std; Int main() { int i; char *p = " Это короткая строка."; i = reinterpret_cast< int> (p); // Приводим указатель к типу int. cout < < i; return 0; } Здесь оператор reinterpret_cast преобразует указатель p в целочисленное значение. Данное преобразование представляет фундаментальное изменение типа. Сравнение обычной операции приведения типов с новыми четырьмя cast-операторами Кому-то из читателей могло бы показаться, что описанные выше четыре cast-оператора полностью заменяют традиционную операцию приведения типов. И тогда у них может возникнуть такой вопрос: " Стоит ли всегда вместо обычной операции приведения типов использовать более новые средства? " . Дело в том, что общего правила для всех программистов не существует. Поскольку новые операторы были созданы для повышения безопасности довольно рискованной операции приведения одного типа данных к другому, многие С++-программисты убеждены, что их следует использовать исключительно с этой целью. И здесь трудно что-либо возразить. Другие же программисты считают, что поскольку традиционная операция приведения типов служила им " верой и правдой" в течение многих лет, то от нее не стоит так легко отказываться. Например, для выполнения простых и относительно безопасных операций приведения типов (как те, что требуются при вызове функций ввода-вывода read() и write(), описанных в предыдущей главе) " старое доброе" средство вполне приемлемо. Существует еще одна точка зрения, с которой трудно не согласиться: при выполнении операций приведения полиморфных типов определенно стоит использовать оператор dynamic_cast. Популярное:
|
Последнее изменение этой страницы: 2016-03-17; Просмотров: 1223; Нарушение авторского права страницы