Саммерфилд Марк
Шрифт:
В некоторых компиляторах оператор dynamic_cast<T> не работает через границы динамических библиотек. Он также рассчитывает на поддержку компилятором технологии RTTI, а эта поддержка может быть отключена программистом для уменьшения размера своих исполняемых модулей. Qt решает эти проблемы, обеспечивая оператор приведения qobject_cast<T> для подклассов QObject.
• const_cast<T> добавляет или удаляет спецификатор const из указателя или ссылки. Например:
В предыдущем примере мы убрали спецификатор const при приведении типа указателя this для вызова неконстантной функции—члена recomputeInternalData. Не рекомендуется так делать, и, если использовать ключевое слово mutable, этого можно избежать, как это делается в главе 4 («Реализация функциональности приложения»).
• reinterpret_cast<T> преобразует любой тип указателя или ссылки в любой другой их тип. Например:
В Java и C# любая ссылка может храниться при необходимости как ссылка на Object. С++ не имеет никакого универсального базового класса, но предоставляет специальный тип данных void *, который содержит адрес экземпляра любого типа. Указатель void * необходимо привести к другому типу (используя static_cast<T>) перед его использованием.
С++ обеспечивает много способов приведения типов, однако в большинстве случаев это даже не приходится делать. При использовании таких классов—контейнеров, как std::vector<T> или QVector<T>, мы можем задать тип T и извлекать элементы без приведения типа. Кроме того, для элементарных типов некоторые преобразования происходят неявно (например, преобразование char в int), а для пользовательских типов можно определить неявные преобразования, предусматривая конструктор с одним параметром. Например:
Автоматическое преобразование, обеспечиваемое некоторыми конструкторами с одним параметром, имеет мало смысла. Его можно отключить, если объявить конструктор с ключевым словом explicit:
Перегрузка операторов
С++ позволяет нам перегружать функции, т.е. мы можем объявлять несколько функций с одним именем в одной и той же области видимости, если они имеют различные списки параметров. Кроме того, С++ поддерживает перегрузку операторов, позволяя назначать специальную семантику встроенным операторам (таким, как +, << и [ ]) при их применении для пользовательских типов.
Мы уже видели несколько примеров с перегруженными операторами. Когда использовался оператор << для вывода текста в поток cout или cerr, мы не пользовались оператором С++, выполняющим поразрядный сдвиг влево, но использовали специальную версию этого оператора, принимающего слева объект потока ostream (например, cout или cerr), а справа — строку (либо вместо строки число или манипулятор потока, например endl) и возвращающего объект ostream, что позволяет несколько раз вызывать оператор в одной строке.
Красота перегрузки операторов заключается в возможности сделать поведение пользовательских типов в точности таким же, как поведение встроенных типов. Чтобы показать, как работает такая перегрузка, мы перегрузим операторы +=, —=, + и —, добавив возможность работы с объектами Point2D: