- •И. А. Андрианов, д. В. Кочкин, с. Ю. Ржеуцкая
- •Учебное пособие
- •Оглавление
- •1. Основы языка 8
- •1.2.2 Простые типы данных 13
- •2. Работа с памятью 73
- •3. Основы объектно-ориентированного программирования 87
- •4.Обработка исключений 114
- •5. Шаблонные функции и классы. Библиотека стандартных шаблонов 130
- •6. Паттерны проектирования 159
- •7. Антипаттерны 211
- •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.5 Разработка шаблонных классов с настраиваемой функциональностью
- •5.6 Использование шаблонов для вычислений на этапе компиляции
- •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 Методики оптимизации кода
- •Заключение
- •Библиографический список
3.2.1 Описание класса
В С++ для описания класса введён новый составной тип class. Кроме того, понятие структуры (struct) и объединения (union) расширено до поддержки концепции ООП. Таким образом, при описании класса можно пользоваться всеми тремя типами. Далее мы будем употреблять термин "класс", вне зависимости от того, каким способом выполнено его описание.
Заметим, что ключевое слово union используется в ООП достаточно редко и для специфических применений. А class и struct можно рассматривать как очень близкие языковые понятия. Небольшая синтаксическая разница между class и struct все-таки есть, чуть позже мы ее поясним. Итак, в общем виде описание (определение) класса выглядит так:
class | struct | union {тело класса};
В теле класса указываются все составляющие его элементы. Для полей указываются имена, типы и возможные спецификаторы. Для методов можно указать их прототипы или полные определения. Рекомендуется в теле класса размещать определения только для очень коротких методов, а большинство методов реализовывать за пределами класса. Определения классов обычно размещаются в файлах с расширением .h, а реализация методов – в файлах с расширением .cpp. Такой подход имеет сразу два преимущества:
определение класса имеет лаконичный и удобный для восприятия вид, особенно при удачно подобранных названиях элементов класса;
реализация методов класса в отдельных файлах позволяет значительно ускорить компиляцию больших проектов, так как большая часть кода будет компилироваться только один раз.
Примеры описаний классов мы приведём чуть позже, когда уясним ещё несколько конструкций, связанных с ООП.
3.2.2 Область видимости элементов класса. Инкапсуляция
Все элементы класса (и поля, и методы) можно разделить на три группы в зависимости от их области видимости:
public:
открытые элементы, к которым имеется доступ из любого участка программы, использующей класс
private:
скрытые элементы, которыми можно пользоваться только при реализации методов этого класса. Больше они нигде не доступны.
protected:
защищенные элементы можно использовать при реализации методов этого класса и его потомков (т.е. область видимости немного шире, чем у элементов из группы private)
Возможность управления областью видимости каждого элемента класса по отдельности позволяет воплотить на практике принцип инкапсуляции.
Поля класса обычно объявляют в ограниченной области видимости private или protected (в расчёте на будущих наследников). Таким образом, прикладная программа, использующая класс, не может записать в поля любые значения, среди которых могут оказаться и недопустимые. Доступ к полям надёжнее выполнять через методы, которые не позволят занести в поля недопустимые значения. Отсюда и термин "инкапсуляция" – поля как бы заключены в капсулу из защищающих их методов.
Возможны и исключения из этого правила – в некоторых случаях поля не нуждаются в защите через методы. Этот вопрос нужно решать индивидуально, исходя из специфики класса и его полей.
Многие методы класса делают открытыми, чтобы ими можно было пользоваться, за исключением тех, которые носят служебный характер.
Теперь, наконец, пришло время сказать, в чём заключается отличие описаний класса с использованием типов class и struct.
Область видимости по умолчанию для типов class и struct. Если при описании класса область видимости каких-либо элементов явно не задана, то для типа class подразумевается private, а для типа struct – public. Можно и так сказать, что тип класса более надёжно защищает свои элементы (даже от невнимательности программиста).
Методы-константы. Можно считать эту возможность ещё одним (дополнительным) способом защиты полей класса. Она заключается в том, что при описании методов, которые не изменяют значений полей класса, можно добавить в заголовок спецификатор const – он помещается в конец заголовка после списка формальных параметров. Наличие этого спецификатора заставляет компилятор выполнить дополнительную проверку, чтобы убедиться, что данный метод действительно не меняет значения ни одного из полей, т.е. он относится к методам-константам.
Спецификатор const никак не влияет на функциональность метода, однако, его применение рекомендуется для повышения надёжности программного кода.
Создание и использование объектов в С++. Как уже было сказано, объекты − это переменные заданного класса, поэтому работа с ними выполняется, как и с переменными других типов.
Глобальные объекты создаются во время запуска программы. Для того чтобы создать глобальный объект, необходимо его объявить вне функции main и других функций:
К таким объектам можно обратиться из любой точки программы. Главное − следить за изменениями данных объектов, т.к. неуправляемое изменение глобальных объектов может вести к трудно находимым ошибкам.
Автоматические объекты создаются при входе в функцию и удаляются при выходе из неё. Использование данного объекта возможно только в пределах этой функции.
Управляемые объекты создаются и удаляются с помощью операторов new и delete. При создании эти объекты помещаются в "кучу", поэтому очень важно следить за тем, чтобы каждому new соответствовал оператор delete, иначе будут утечки памяти.
Для обращения к полям и методам объектов используются символы "." и "->”. Точка используется, когда к объекту обращаются по имени. Операция "->" используется когда обращаются к объекту через указатель на объект.
Теперь мы получили достаточно информации, чтобы перейти к примерам.
