Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Программирование основы языка С++. Учебное пособие

.pdf
Скачиваний:
0
Добавлен:
07.09.2026
Размер:
2 Мб
Скачать
☆
собственные литералы (user-defined literals). Для создания собственного литерала используется синтаксис похожий на перегрузку операций.
4.7 Константы в С++
Константы в С++ аналогичны константам в Си. Для представле­ния константы в Си использовалась только директива препроцессора #define:
#define MAX 100
В С++ для представления константы рекомендуется использовать объявление переменной с начальным значением и ключевым словом const:
const тип ИмяПеременной = НачальноеЗначение;
const int n=10;
Область видимости константы такая же, как у обычной перемен­ной. С помощью ключевого слова const можно объявить указатель на константу:
const тип *ИмяПеременной;
const int *m; // m – указатель на константу типа int
const int n=3;
m = &n;
Еще одна возможность const состоит в создании постоянного ука­зателя на величину указанного типа:
тип *const ИмяПеременной = Значение;
int i;
int *const ptri=&i;
Использование const имеет несколько преимуществ по сравнению с #define. При объявлении константы с использованием const явно указы-
вается тип величины. Константа, объявленная с использванием const, просто согласуется с производными типами, например, объявление массива:
const int base_vals[5] = { 1000, 2000, 3500, 6000, 10000};
Идентификаторы const подчиняются тем же правилам, что и пере­менные. Можно создавать константы с различной областью видимости.
51
4.8 Перечислямый тип данных
В С++ можно создавать свои типы данных. Для реализации соб-
ственного типа данных используется перечисляемый тип данных.
Перечисление («перечисляемый тип») – это тип данных, где любое значение (или еще «перечислитель») определяется как символьная кон­станта. Объявляется перечисление с помощью ключевого слова enum:
//объявляем новый тип данных Месяц
enum Months
{
//здесь перечисляем все возможные значения
//каждый разделитель разделяется запятой(!)
JANUARY,
FEBRUARY,
MARCH,
APRIL,
MAY,
JUNE,
JULY,
AUGUST,
SEPTEMBER,
OCTOBER,
NOVEMBER,
DECEMBER
}; //enum обязательно заканчивается точкой с запятой
Months my_month= JANUARY; //определяем переменную my_month типа
enum
Объявление перечислений не требует выделения памяти, только когда переменная перечисляемого типа определена, тогда и выделяется память для этой переменной.
Идентификаторы перечислений начинаются с заглавной буквы, а имена перечислителей состоят только из заглавных букв. Так как пере­числители находятся в одном пространстве имен с перечислением, по­этому одно и то же имя одного перечислителя не может быть использо­вано в нескольких перечислениях одного и того же пространства имен:
enum Months
{
JANUARY, //данный перечислитель находится в глобальном простран­тсве имен
52
FEBRUARY, MARCH };
enum Size { JANUARY, // ошибка, т.к. уже используется данный перечислитель BIG, SMALL };
Каждому перечислителю автоматически присваивается целочис­ленное значение в зависимости от его позиции в списке перечисления. Можно назначать значения самостоятельно, при этом не определенные перечислители будут иметь значения на 1 больше, чем значения пре­дыдущего. При этом необходимо иметь ввиду, что присваивать одно и тоже значение разным перечислителям не рекомендуется. По умолча­нию, первому перечислителю присваивается целое число 0, а каждому следующему – на единицу больше, чем предыдущему:
enum Months
{
JANUARY, //=0
FEBRUARY, //=1
MARCH, //=2
APRIL, //=3
MAY, //=4
JUNE, //=5
JULY, //=6
AUGUST, //=7
SEPTEMBER, //=8
OCTOBER, //=9
NOVEMBER, //=10
DECEMBER //=11
};
При использовании перечислителей необходимо иметь ввиду, что компилятор будет работать с присвоенными значениями, и, следова­тельно, не позволит осуществлять ввод/вывод перечислителей через стандартный ввод/вывод:
53
#include <iostream> enum Months
{ JANUARY, //=0 FEBRUARY, //=1 MARCH, //=2 APRIL, //=3 MAY, //=4 JUNE, //=5 JULY, //=6 AUGUST, //=7 SEPTEMBER, //=8 OCTOBER, //=9 NOVEMBER, //=10 DECEMBER //=11 };
int main() { Months my_m, my_m1=JUNE; std::cin >> my_m; //ошибка std::cout << my_m1; //выведет 5 return 0; }
4.9 Преобразование типов
4.9.1 Оператор явного преобразования типа: (). В C++ разрешаются явные преобразования типов с использованием синтаксиса, аналогич­ного синтаксису вызова функции:
simple-type-name (expression-list)
Явное преобразование типа в тип int:
int i = int( d );
Явное преобразование типа а тип float:
int i = 7; float d; d = float( i );
Явные преобразования типов также можно задавать с помощью
синтаксиса приведения:
54
d = (float)i;
Преобразования отдельных значений в стиле приведения и в сти­ле функции дают одинаковые результаты. Однако в синтаксисе стиля функции можно определить несколько аргументов для преобразования.
Внимание! Явные преобразования типов следует использовать с осторожностью, поскольку они переопределяют встроенную проверку типов компилятора C++.
4.9.2 Стандартные преобразования. В языке C++ определены преоб­разования между его основными типами. Также определяются преобра­зования для указателей, ссылочных типов и типов указателей на члены, такие преобразования называются стандартными преобразованиями:
восходящие приведения целочисленных типов;
•
преобразования целочисленных типов;
•
преобразования типов с плавающей запятой;
•
преобразования типов с плавающей запятой и целочисленных типов;
•
арифметические преобразования;
•
преобразования указателей;
•
преобразования ссылок;
•
преобразования указателей на члены.
•
Восходящие приведения целочисленных типов. Объекты целочислен-
ного типа можно преобразовать в другой более широкий целочисленный тип, то есть тип, который может представлять больший набор значений. Этот расширяющий тип преобразования называется целочисленным по- вышением. С помощью целочисленного повышения можно использовать следующие типы в выражении, где можно использовать другой цело­численный тип:
объекты, литералы и константы типа char и short int
•
типы перечисления.
•
битовые поля int
•
перечислители.
•
Обычно при повышениях с сохранением значения и повышениях с сохранением наличия знака выдаются одинаковые результаты. Однако они могут дать разные результаты, если объект повышенного уровня выглядит следующим образом:
Операнд /, %, /=, %=, <, <=, > или >= – эти операторы зависят от
•
знака для определения результата. При применении к этим операндам предложения с сохранением и обслуживанием, сохраняя при этом подписи, получают разные результаты.
55
Левый операнд >> или >>= – эти операторы обрабатывают ко-
•
личества со знаком и без знака по-разному в операции сдвига. Для количества со знаком операция сдвига вправо распространяет бит знака на освобожденные позиции битов, а освобожденные разряды заполняются нулем в неподписанных количествах.
Аргумент для перегруженной функции или операнд перегруженного
•
оператора, который зависит от подписи типа операнда для соответ­ствующего аргумента. Дополнительные сведения об определении перегруженных операторов см. в разделе перегруженные операторы.
Преобразования целочисленных типов
Целочисленные преобразования – это преобразования между цело­численными типами. Целочисленные типы – char, Short (или short int), int, Longи long long. Эти типы могут быть дополнены со знаком или без знака.
Преобразование чисел со знаком в числа без знака. Объекты цело­численных типов со знаком можно преобразовывать в соответствующие типы без знака. При возникновении этих преобразований фактический битовый шаблон не изменяется:
#include <iostream>
using namespace std;
int main()
{
// определяется и задается короткое значение со знаком, i, которое инициализируется с
// отрицательным числом
short i = –3;
unsigned short u;
//(u = i) выражения приводит к тому, что i преобразуются в непод­писанный короткий промежуток перед присваиванием u
cout << (u = i) << "\n";
}
// Output: 65533
Преобразование чисел без знака в числа со знаком. Объекты цело­численных типов без знака можно преобразовывать в соответствующие типы со знаком. Однако если значение без знака находится за предела­ми представимого диапазона типа со знаком, результат не будет иметь правильное значение, как показано в следующем примере:
#include <iostream>
56
using namespace std; int main() { short i; unsigned short u = 65533; // u является неподписанным коротким целым объектом, который
необходимо
// преобразовать в число со знаком, чтобы вычислить выражение (i = u). cout << (i = u) << "\n"; } // поскольку его значение не может быть правильно представлено ко-
ротким знаком,
// данные будут неправильно интерпретированы //Output: –3
Преобразование чисел с плавающей запятой. Объект типа с плава­ющей запятой можно безопасно преобразовать в более точный тип с плавающей запятой, то есть без потери значимости. Например, при пре­образовании с плавающей запятой в Double или из двойного в длинное двойное значение может быть безизменным. Объект плавающего типа также можно преобразовать в менее точный тип, если он находится в диапазоне, представленном этим типом. Если исходное значение не может быть представлено точно, его можно преобразовать в следующее большее или следующее более низкое значение. Если такого значения не существует, результат будет неопределенным. Рассмотрим следую­щий пример:
std::cout << (float)1E300 << std::endl;
Максимальное значение, которое может быть представлено типом float , – это 3.402823466E38 – намного меньшее число, чем 1E300. Таким образом, число преобразуется в бесконечное значение, а результатом является "INF".
Преобразования между целочисленным типом и типом с плавающей запятой. Определенные выражения могут вызывать преобразование
объектов плавающего типа в целочисленные типы, и наоборот. Если объект целочисленного типа преобразуется в тип с плавающей запятой, а исходное значение не может быть представлено точно, результатом является либо следующее выше, либо следующее меньшее представимое значение. При преобразовании объекта с плавающего типа в целочис­ленный тип дробная часть усекаетсяили округляется в сторону нуля.
57
Число, например 1.3, преобразуется в 1, а (-1.3) преобразуется в (-1). Если усеченное значение выше наибольшего допустимого значения или меньше наименьшего представимого значения, результат будет неопределенным.
Арифметические преобразования. Многие бинарные операторы при­водят к преобразованию операндов и выдают результаты одинаковым образом. Арифметические преобразования операндов, которые имеют различные собственные типы, выполняются, как показано на рисун­ке 4.1. Типы typedef ведут себя в соответствии со своими базовыми собственными типами.
Рисунок 4.1
Преобразования указателей. Указатели можно преобразовывать в ходе присваивания, инициализации, сравнения и выполнения других выражений.
Указатель на классы. Указатель на класс можно преобразовать в ука­затель на базовый класс в двух случаях:
Во-первых, когда указанный базовый класс доступен и преобразова­ние однозначно. Дополнительные сведения об неоднозначных ссылках
58
на базовые классы см. в разделе несколько базовых классов. Доступность базового класса зависит от используемого типа наследования (рис. 4.2).
Рисунок 4.2 – допустимость преобразования
Во-вторых, указатель на класс можно преобразовать в указатель на базовый класс при использовании явного преобразования типов. Результатом такого преобразования является указатель на подобъект, часть объекта, полностью описываемого базовым классом.
Указатель на функцию. Указатель на функцию можно преобразовать в тип void *, если тип void * достаточно большой для хранения этого указателя.
Указатель на void. Указатели на тип void можно преобразовать в ука­затели на любой другой тип, но только с явно приведенным типом. Указатель на любой тип можно преобразовать неявно в указатель на тип void. Указатель на неполный объект типа может быть преобразован в указатель на void (неявно) и обратно (явно). Результат такого преобра­зования равен значению исходного указателя. Объект считается непол­ным, если он объявлен, но недостаточно информации для определения его размера или базового класса. Указатель на любой объект, который не является константой или volatile, может быть неявно преобразован в указатель типа void *.
59
4.10 Контрольные вопросы
1. Язык программирования C++ разработал: a. Никлаус Вирт b. Кен Томпсон c. Дональд Кнут d. Бьерн Страуструп
2. Простые типы данных в С++: a. целые – int, вещественные – float или double, символьные – string b. целые – int, вещественные – float или real, символьные – char c. целые – int, вещественные – float или double, символьные – char d. целые – bool, вещественные – float или double, символьные –
string
3. Какой из перечисленных типов данных не является типом данных
в С++?
a. float b. int c. real d. double
4. Какой оператор не допускает перехода от одного константного
выражения к другому?
a. end; b. Stop; c. точка с запятой d. break;
1. Какие служебные символы используются для обозначения начала
и конца блока кода?
a. < > b. begin end c. ( ) d. { }
6. Укажите правильное определение функции main в соответствии
со спецификацией стандарта ANSI:
a. void main() b. int main(void) c. void main(void) d. int main()
7. Выберите правильный вариант объявления константной перемен-
ной в С++, где type - тип данных в С++ variable - имя переменной value -
60
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]