
- •1 Использование описания typedef
- •2 Преобразование типов
- •3 Указатели на функции
- •4 Пример использования указателей на функции
- •5 Области видимости и время жизни объектов
- •6 Пример использования статической локальной переменной
- •Примечание
- •7 Пространства имен
- •8 Заголовочные файлы
- •9 Подходы к разработке структуры программы
- •11 Задания на самостоятельную работу Задание 1
- •Задание 2
Тема 7
Преобразование типов. Указатели на функции. Cтруктура программы |
1 Использование описания typedef
Описания typedef позволяет вводить синонимы для определенных ранее типов. Имена, определенные с помощью typedef, можно использовать так же, как спецификаторы встроенных типов и производных типов, а также типов, определенных пользователем. В описании после ключевого слова typedef следует спецификатор типа и идентификатор. Этот идентификатор и есть синоним для указанного типа.
typedef int *PArray[10]; // Тип массива из 10 указателей на целое
PArray p; // Переменная описанного типа
Синонимы типов, определенные с помощью typedef, могут участвовать в другом определении typedef. Описание typedef не определяет нового (пользовательского) типа, а только определяет синоним для существующего.
Наряду с базовыми типами данных, имена типов, полученные с помощью описания typedef, можно использовать в таких операциях, как приведение типа, sizeof, new, а также в объявлениях.
2 Преобразование типов
В некоторых случаях в пределах одного выражения фигурируют данные различных типов. Если это возможно, применяются неявные преобразования типов всякий раз, когда смешиваются различные типы данных. Можно рассмотреть следующие случаи:
В арифметическом выражение с операндами разных типов все операнды приводятся к наибольшему типу из встретившихся. Это называется арифметическим преобразованием.
При присваивании значения выражения одного типа объекту другого типа результирующим является тип объекта, которому значение присваивается.
При передач функции аргумента, тип которого отличается от типа соответствующего формального параметра, тип фактического аргумента приводится к типу параметра.
Если тип объекта требует для своего представления меньше битов (является более узким типом), чем тип присваиваемого объекту значения, то говорят, что происходит сужение типа. Сужение типа может привести к потере данных. Преобразование беззнакового типа к знаковому тоже считается сужением типа. В арифметическом выражении более широкий тип данных становится результирующим типом - это расширение типа.
В приведенном фрагменте программы
int i = 3.14;
i = i + 3.14;
произойдут три преобразования типа. Константа 3.14 преобразуется к типу int (i равно 3). Во второй строке значение i расширяется до double. Результат 6.14 затем сужается до int. Это суженное значение присваивается i. Переменная i теперь содержит значение 6.
Явное преобразование типов производится при помощи следующих операторов: static_cast, dynamic_cast, const_cast и reinterpret_cast. Хотя иногда явное преобразование необходимо, оно служит потенциальным источником ошибок, поскольку подавляет проверку типов, выполняемую компилятором.
С применением static_cast осуществляются те преобразования, которые могут быть сделаны неявно, на основе правил по умолчанию. С помощью static_cast указатель void* можно преобразовать в указатель определенного типа, арифметическое значение – в значение перечисления (enum), а базовый класс – в производный. Данное преобразование работает только для связанных типов и только во время компиляции, что позволяет не смешивать различные подходы к преобразованиям. В следующем примере преобразование выполняется для того, чтобы на экран выводилось число, а не символ с соответствующим кодом:
char byte_value = 32;
cout << static_cast<int>(byte_value);
Оператор dynamic_cast применяется при идентификации типа во время выполнения (run-time type identification) и будет рассмотрен при изучении классов.
Преобразование const_cast используется для добавления или удаления из типа переменной модификаторов const и volatile (последний модификатор используется для отображения того факта, что переменная может быть изменена фоновым процессом, подпрограммой-обработчиком прерываний и т.д.). В выражении
const_cast< T > (arg)
T и arg должны быть одного и того же типа, за исключением модификаторов const и volatile. Преобразование осуществляется во время выполнения. Результат имеет тип T. Чаще всего используется для преобразования типов указателей и ссылок:
int i = 2;
const int *p1 = &i;
int* p2 = const_cast<int*>(p1); // Без const_cast будет ошибка компиляции
*p2 = 3; // Можно модифицировать i через p2
Преобразование reinterpret_cast работает с внутренними представлениями объектов (re-interpret – другая интерпретация того же внутреннего представления), причем правильность этой операции целиком зависит от программиста. В выражении
reinterpret_cast< T > (arg)
тип T должен быть типом указателя, ссылки, арифметическим типом, указателем на функцию или член класса.
Устаревшая форма явного преобразования имеет два вида:
// появившийся в C++ вид
type (expr);
// вид, существовавший в C
(type) expr;
и может применяться вместо операторов static_cast, const_cast и reinterpret_cast.