- •И. А. Андрианов, д. В. Кочкин, с. Ю. Ржеуцкая
- •Учебное пособие
- •Оглавление
- •1. Основы языка 8
- •1.2.2 Простые типы данных 13
- •6. Паттерны проектирования 159
- •7. Антипаттерны 211
- •2. Работа с памятью 73
- •3. Основы объектно-ориентированного программирования 87
- •4.Обработка исключений 114
- •5. Шаблонные функции и классы. Библиотека стандартных шаблонов 130
- •9. Методы отладки и оптимизации кода 242
- •1. Основы языка
- •1.1.2 Понятие проекта
- •1.2 Простые типы данных
- •1.2.1 Понятие типа
- •1.2.2 Простые типы данных
- •1.2.3 Внутреннее представление простых типов
- •1.2.4 Ключевое слово typedef. Тип size_t
- •1.3 Константы и переменные
- •1.3.1 Литералы
- •1. Числовые константы:
- •2. Символьные константы:
- •1.3.2 Переменные
- •1.3.3 Описание переменных
- •1.4. Выражения. Преобразование типов
- •1.4.1 Операнды и операции
- •1.4.2 Приоритет операций
- •1.4.3 Преобразование типов
- •1.5 Ветвления и циклы
- •1.5.2 Циклы
- •1.6 Массивы, строки
- •1.6.1 Основные понятия
- •1.6.2 Встроенные массивы
- •1.6.3 Cтроки. Обработка строк с завершающим нулём
- •1.7 Указатели и ссылки. Связь указателей и массивов. Библиотека cstring
- •1.7.1 Понятия указателя и ссылки
- •1.7.2 Связь между массивами и указателями
- •1.7.3 Библиотека cstring
- •1.8 Использование типов vector и string
- •1.8.1 Шаблонный класс vector
- •1.8.2 Класс string
- •1.9 Структуры и объединения. Битовые поля
- •1.10.1 Понятие функции
- •1.10.2 Описание функции и прототип функции
- •1.11 Параметры функции. Способы передачи параметров
- •1.11.1 Параметры функции и глобальные переменные
- •1.11.2 Способы передачи параметров в функцию
- •1.11.3 Передача массивов в функцию
- •1.11.4 Параметры-константы
- •1.11.5 Значения параметров по умолчанию
- •1.12.1 Указатель на функцию
- •1.12.2 Функции с переменным числом параметров
- •1.12.3 Перегрузка функций
- •1.12.4 Встроенные (inline) функции
- •1.13 Рекурсивные функции
- •1.14 Пространства имён
- •1.15 Директивы препроцессора. Макросы
- •2. Работа с памятью
- •2.1 Управление выделением и освобождением памяти
- •2.1.1 Статическое и динамическое выделение памяти
- •2.1.2 Способы динамического выделения и освобождения памяти
- •2.2 Динамические структуры данных
- •2.2.1 Основные понятия
- •2.2.2 Примеры реализации динамических структур на основе указателей
- •3. Основы объектно-ориентированного программирования
- •3.1 Основные понятия ооп
- •3.2.1 Описание класса
- •3.2.2 Область видимости элементов класса. Инкапсуляция
- •3.2.3 Первые примеры
- •3.3. Конструкторы и деструкторы.
- •3.4 Указатель this
- •3.5 Перегрузка операций
- •3.6 Дружественные функции и классы
- •3.7 Статические элементы класса
- •3.8 Наследование и полиморфизм
- •3.8.1. Основные понятия
- •3.8.2 Одиночное наследование
- •3.8.3 Множественное наследование
- •3.8.4 Конструкторы и деструкторы классов-потомков
- •3.9. Полиморфизм при наследовании классов
- •3.9.1 Механизмы раннего и позднего связывания
- •3.9.2 Абстрактные классы
- •4.Обработка исключений
- •4.1 Основные понятия
- •4.2 Перехват исключений
- •4.3 Поиск обработчика исключений. Раскрутка стека.
- •4.4 Повторное возбуждение исключений
- •4.5 "Аппаратные" и "программные" исключения
- •4.6 Стандартные классы исключений
- •4.7 Спецификация исключений, возбуждаемых функцией
- •4.8 Исключения в конструкторах при наследовании
- •4.9. Исключения в деструкторах
- •5. Шаблонные функции и классы. Библиотека стандартных шаблонов
- •5.1 Шаблонные функции
- •5.2 Шаблонные классы
- •5.3 Специализация шаблонов
- •5.4 Шаблонные параметры шаблонов
- •5.6 Использование шаблонов для вычислений на этапе компиляции
- •5.5 Разработка шаблонных классов с настраиваемой функциональностью
- •5.7 Библиотека стандартных шаблонов (stl) – основные понятия
- •5.8 Последовательные контейнеры. Итераторы
- •5.9. Адаптеры контейнеров
- •5.10 Ассоциативные контейнеры
- •5.11 Алгоритмы
- •6. Паттерны проектирования
- •6.1 Порождающие шаблоны
- •6.2 Структурные шаблоны
- •6.3 Шаблоны поведения
- •6.4 Шаблон "фабричный метод" (Factory method)
- •6.5 Шаблон "одиночка" (Singleton)
- •6.6 Шаблон "итератор" (Iterator)
- •6.7 Шаблон "наблюдатель" (Observer)
- •6.8 Шаблон "пул объектов" (Object pool)
- •6.9 Шаблон "команда" (Command)
- •6. 10 Шаблон "посетитель" (Visitor)
- •6.11 Дополнительные задания
- •6.11.1 Шаблон Iterator
- •6.11.2 Шаблон Observer
- •6.11.3 Шаблоны Command и Observer
- •6.11.5 Шаблон Visitor
- •6.11.5 Разработка класса − контейнера
- •6.11.6 Оценка производительности кода
- •7. Антипаттерны
- •7.1 Программирование методом копирования и вставки (Copy-Paste Programming)
- •7.2 Спагетти-код (Spaghetti code)
- •7.3 Магические числа (Magic numbers)
- •7.4 Бездумное комментирование
- •7.5 Жесткое кодирование (Hard code)
- •7.6 Мягкое кодирование (Soft code)
- •7.7 Золотой молоток (Golden hammer)
- •7.8 Слепая вера (Blind faith)
- •7.9 Ненужная сложность (Accidental complexity)
- •7.10 Божественный объект (God Object)
- •7.11 Лодочный якорь (Boat anchor)
- •7.12 Поток лавы (Lava flow)
- •7.13 Изобретение велосипеда (Reinventing the wheel)
- •7.14 Программирование перебором (Programming by permutation)
- •8.1 Выведение типов
- •8.2 Списки инициализации
- •8.3 Улучшение процесса инициализации объектов
- •8.4 Цикл for по коллекции
- •8.5 Лямбда-функции
- •8.6 Константа нулевого указателя nullptr
- •8.7 "Умные" указатели
- •9. Методы отладки и оптимизации кода
- •9.1 Отладка кода
- •9.1.1 Основные этапы отладки
- •9.1.2 Инструменты и приёмы отладки
- •9.2 Оптимизация кода
- •9.2.1 Рекомендации по выполнению оптимизации
- •9.2.2 Методики оптимизации кода
- •Заключение
- •Библиографический список
1.2 Простые типы данных
1.2.1 Понятие типа
Любая переменная, константа, значение выражения или результат функции относятся к определенному типу данных.
Тип данных определяет множество допустимых значений данных и набор операций над этими значениями. Информация о типе данных используется компилятором при выделении памяти для данных – размер выделяемой области памяти определяется в зависимости от типа.
Типы данных, используемые в С++, можно разделить на группы:
простые (скалярные);
составные (сложные);
указатели и ссылки;
пустой тип (void).
Составные типы используются для определения совокупностей данных. В языке С++ и его стандартной библиотеке имеется множество стандартных составных типов, также поддерживается возможность создания новых типов (классов – в терминологии объектно-ориентированного программирования).
Указатели и ссылки – особые типы, которые обеспечивают возможность косвенного доступа к объектам (переменным или функциям), используя их адреса в памяти или альтернативные имена (псевдонимы).
Внутреннее представление данных различных типов в памяти и детали реализации операций предоставляются на усмотрение разработчиков компиляторов. Однако, в стандарте определена операция sizeof(тип | переменная), возвращающая размер области памяти в байтах, отводимой под переменную данного типа.
1.2.2 Простые типы данных
Систематизация простых типов представлена на рисунке 1.1.
Рисунок 1.1 Простые типы данных
Обратим внимание, что к целочисленным относят также символьные типы и логический тип, имея в виду, что внутреннее представление символов и логических значений – целые числа.
Возможен другой вариант систематизации по множеству допустимых значений, не учитывающий особенности внутреннего представления:
логический тип
символьные типы
числовые типы (целые, вещественные, перечисления);
Разберёмся с правилами синтаксиса. В обозначениях простых типов в С++ могут присутствовать слова-модификаторы, позволяющие изменить диапазон допустимых значений основного типа:
shot (короткий), long (длинный);
signed (со знаком – можно явно не указывать), unsigned (без знака).
Их применение рассмотрим для каждого типа отдельно.
Логический тип имеет обозначение bool и принимает значения true и false. Его размер – 1 байт, при этом значение 0 в этом байте соответствует false, а любое ненулевое значение соответствует true. Ни в каких словах-модификаторах данный тип не нуждается.
Символьные типы. Основной символьный тип – char, который по стандарту имеет размер 1 байт и используется для хранения кодов символов в соответствии с таблицей ASCII (American Standard Code for Information Interchange — американский стандартный код для обмена информацией). Он часто обозначается с модификатором unsigned (т.е. unsigned char), чтобы полностью соответствовать таблице ASCII, в которой все допустимые символы имеют коды от 0 до 255. Символы с 0-го по 31-й являются неотображаемыми на экране монитора, символ с кодом 32 означает пробел, а коды некоторых других символов следующие:
'0'...'9' – 48...57, 'A'...'Z' – 65...90, 'a'...'z' – 97...122
Символы с кодами больше 127 (вторая половина кодовой таблицы) соответствуют символам национальных алфавитов (в нашем случае – кириллицы). К сожалению, имеется несколько различных вариантов кодировки кириллицы, поэтому могут возникнуть проблемы с некорректным выводом символов русского языка. В большинстве случаев эти проблемы снимаются с помощью функции setlocale (см. пример 1.1).
Ещё один символьный тип – wchar_t (wide char type), использующийся для работы с символами расширенных кодовых таблиц, в которых для представления символа одного байта недостаточно. В настоящее время такой таблицей является Unicode, в ней символы могут кодироваться числовыми кодами, занимающими более одного байта, – проблем с выводом кириллицы практически не возникает. Размер wchar_t в стандарте не определен, но имеются два дополнительных типа с определенными размерами wchar16_t (2 байта) и wchar32_t (4 байта). В настоящее время практически все известные компиляторы поддерживают размер 2 байта для wchar_t.
Целые типы. Имеется только один основной целый тип – int, к которому применимы модификаторы short и long (допустимо long long – очень длинное целое), а также signed (по умолчанию) и unsigned. Таким образом, можно сформировать несколько целых типов с различными диапазонами значений.
Обратим внимание, что при применении слов-модификаторов к типу int само слово int можно не указывать (например, short и short int – синонимы).
Размеры целых типов в стандарте не определены, но имеется правило:
sizeof(short) <= sizeof(int) <= sizeof(long)<=sizeof(long long)
Например, компилятор MS Visual C++ поддерживает следующие размеры целых типов (в байтах): short – 2, int и long – 4, long long – 8.
В стандарте С++11 имеются целые типы фиксированной длины – int8_t, int16_t, int32_t, int_64t.
Рассматривая целые типы, коснёмся и производного целого типа, который задаётся перечислением своих допустимых значений, поэтому получил название перечислимого типа или перечисления. Он обозначается:
enum имя_типа(список допустимых значений).
Например:
enum colors(black, white, red, green, blue)
Любая переменная типа colors сможет принимать только те значения, которые перечислены в списке, – все константы из списка имеют тип int, при этом по умолчанию нумеруются с нуля (black=0, white=1 и т.д.)
Применение перечислений, где это возможно, повышает наглядность программы на С++, способствует лучшему пониманию её текста.
Вещественные типы. К ним относятся float, double и long double. Их размеры в стандарте не определены, но известно:
sizeof(float) <= sizeof(double) <=sizeof(long double)
Многие компиляторы поддерживают размер 4 байта для float и 8 байт для double и long double, в gnu c++ long double имеет размер 10 байт.
Кратко поясним особенности внутреннего представления базовых типов в оперативной памяти, поскольку отсутствие знаний в этом случае может привести к ошибкам в программах.
