- •Предисловие
- •Глава 1. Основные понятия
- •1.1. Элементы языка программирования
- •1.2. Процесс создания программы
- •1.3. Первая программа
- •1.4. Состав программы
- •Глава 2. Средства разработки на C++
- •2.1. Системы Turbo C++ 3.0/Borland C++ 3.1
- •2.2. Система C++ Builder
- •Глава 3. Работа с числовыми данными
- •3.1. Целые типы
- •3.2. Числа с плавающей точкой
- •3.3. Ввод и вывод чисел
- •3.4. Логический тип и логические операции
- •3.5. Математические функции
- •Глава 4. Операторы. Ключевые слова
- •4.1. Операторы
- •4.2. Приоритеты операторов
- •4.3. Ключевые слова
- •4.4. Структура программы
- •4.5. Константы
- •Задачи - . Простейшие вычисления
- •Глава 5. Управление и циклы
- •5.1. Условный оператор
- •5.2. Операторы цикла
- •5.3. Переключатель
- •5.4. Операторы break и continue
- •Задачи -. Выбор и циклы
- •Глава 6. Массивы
- •6.1. Одномерные массивы
- •6.2. Двумерные массивы
- •Задачи -. Одно- и двумерные массивы
- •Глава 7. Функции
- •7.1. Определение функции
- •7.2. Формальные параметры и фактические аргументы
- •7.3. Автоматические и статические переменные
- •7.4. Прототипы функций
- •7.5. Массивы как аргументы функций
- •7.6. Внешние переменные
- •7.7. Рекурсия
- •7.8. Перегруженные имена функций
- •7.9. Аргументы функций по умолчанию
- •Задачи -. Функции
- •Глава 8. Символы и строки
- •8.1. Символы
- •8.2. Строки символов
- •Задачи -. Символы и строки
- •Глава 9. Препроцессор
- •9.1. Директивы препроцессора
- •9.2. Макросы
- •Задачи -. Макросы
- •Глава 10. Указатели и ссылки
- •10.1. Указатели и адреса
- •10.2. Указатели и массивы
- •10.3. Адресная арифметика
- •10.4. Символьные указатели
- •10.5. Массивы указателей
- •10.6. Указатели на функции
- •10.7. Ссылки
- •10.8. Операторы new и delete
- •Задачи -. Указатели и ссылки
- •Глава 11. О файлах и командной строке
- •11.1. Знакомство с файлами
- •11.2. Командная строка
- •11.3. Перенаправление стандартного ввода и вывода на файл
- •11.4. Аргументы командной строки
- •Задачи -. Файлы и командная строка
- •Глава 12. Работа с экраном дисплея
- •12.1. Текстовый режим
- •12.2. Графический режим
- •Задачи -. Работа с экраном
- •Глава 13. Внутреннее представление чисел
- •13.1. Двоичная система счисления
- •13.2. Беззнаковые целые
- •13.3. Двоичный дополнительный код
- •13.4. Двоичный код с избытком
- •13.5. Побитовые операторы
- •13.6. Дробные числа в двоичной системе
- •13.7. Внутреннее представление плавающих типов
- •13.8. Преобразование типов
- •Задачи -. Побитовые операторы
- •Глава 14. Структуры, перечисления, объединения
- •14.1. Объявление структур
- •14.2. Структуры и функции
- •14.3. Указатели на структуры
- •14.4. Массивы структур
- •14.5. Перечисления
- •14.6. Объединения
- •14.7. Битовые поля
- •14.8. О бинарных файлах
- •Задачи -. Структуры
- •Глава 15. Классы
- •15.1. Структуры в C++. Инкапсуляция
- •15.2. Встроенные функции
- •15.3. Классы. Скрытие данных
- •15.4. Конструкторы
- •15.5. Статические члены класса
- •15.6. Друзья класса
- •15.7. Копирование объектов класса
- •15.8. Управление доступом
- •15.9. Ссылка на себя
- •15.10. Деструкторы
- •Задачи -. Работа с классами
- •Глава 16. Программы из нескольких файлов
- •16.1. Работа с проектами
- •16.2. Область действия имен
- •16.3. Заголовочные файлы
- •16.4. Пространства имен
- •Задачи -. Работа со стеком
- •Глава 17. Перегрузка операторов
- •17.1. Правила перегрузки операторов
- •Задачи -. Перегрузка операторов
- •Глава 18. Конструктор копирования и оператор присваивания
- •18.1. Проблемы при копировании
- •Задачи -. Конструктор копирования
- •Глава 19. Ввод и вывод
- •19.1. Вывод
- •19.2. Ввод
- •19.3. Ввод и вывод определяемых пользователем типов
- •19.4. Работа с файлами
- •Глава 20. Взаимоотношения классов
- •20.1. Объекты как члены класса
- •20.2. Конструкторы встроенных типов
- •20.3. Наследование
- •20.4. Виртуальные функции
- •20.5. Абстрактные классы
- •20.6. Совместимость типов
- •20.7. Множественное наследование
- •Задачи -. Наследование классов
- •Глава 21. Шаблоны, исключения
- •21.1. Шаблоны
- •21.2. Шаблоны функций
- •21.3. Классы и шаблоны
- •21.4. Обработка исключений
- •21.5. Стандартная библиотека шаблонов
- •Литература
- •Предметный указатель
200
Глава 15. Классы
До сих пор главными инструментами при решении задач у нас были функции. Программирование с использованием функций называется процедурным. В процедурном программировании основное внимание уделяется способам обработки данных, а сами данные находятся немного в стороне.
Классы являются инструментом объектно-ориентированного программирования, в котором во главе угла стоят данные.
Класс – это определяемый пользователем тип. Тип является конкретным представлением некоторой концепции. Например, встроенный тип float вместе с операциями +, -, *, / представляет конкретное воплощение математической концепции вещественного числа. Новые типы создаются для определения концепции, не выражаемой непосредственно встроенными типами.
15.1.Структуры в C++. Инкапсуляция
Вязыке C++ в состав структур могут входить не только данные, как это имеет место в языке C, но и функции. Объединение в структуре и данных и функций для их обработки называется инкапсуляцией. Достоинством инкапсуляции является полное описание модели в одном месте, что упрощает работу с моделью. Функции, входящие в структуру, имеют непосредственный свободный доступ к данным, хранящимся в структуре.
Например, для работы со временем суток можно использовать структуру, описанную в следующей программе.
Программа 41. Время как структура
// Файл StrcTime.cpp #include <iostream.h>
struct Time{ |
// Время суток |
unsigned int h, m; |
// Часы, минуты |
void Set(int hh, int mm) |
// Установка времени |
{h = hh; m = mm;} |
|
void AddHour(int n); |
// Добавить n часов |
void AddMin(int n); |
// Добавить n минут |
void Print(); |
// Печать времени |
}; |
|
Классы 201
В состав структуры Time кроме данных h и m, предназначенных для хранения часов и минут, включены функции: Set, AddHour, AddMin и Print. Функции, объявленные внутри структуры, называются функциями-членами или методами. Данные, хранящиеся в структуре, иногда называют свойствами.
Функция Set определена непосредственно внутри структуры, то есть, написан блок с телом функции, остальные функции в структуре лишь объявлены, так как дан только их заголовок.
Функции, объявленные в структуре, следует где-то определить. При определении функции-члена структуры следует указывать имя структуры, разделяя имя структуры и имя функции оператором
разрешения области видимости (::):
// Продолжение файла StrcTime.cpp
void Time::AddHour(int n) |
// Добавить n часов |
{ |
|
h = (h + n) % 24; |
|
} |
|
Внутри функции-члена обращаться к другим членам структуры можно непосредственно по их именам, то есть можно не писать:
Time::h = (Time::h + n) % 24;
хотя это и допустимо.
void Time::AddMin(int n) |
// Добавить n минут |
{ |
|
h = (h + (m + n) / 60) % 24; |
|
m = (m + n) % 60; |
|
} |
|
void Time::Print() |
// Печать времени |
{ |
|
if(h < 10) cout << '0' << h << ':'; else cout << h << ':';
if(m < 10) cout << '0' << m << ' '; else cout << m << ' ';
}
Вфункции печати времени предусмотрен вывод числа часов и минут с ведущим нулем.
Вглавной функции вводится время начала занятий в вузе, а затем выводятся время конца пары и время начала следующей.
#include <conio.h> void main()
{
202 |
15 |
|
|
Time Pair; |
// Время начала или конца очередной пары |
||
int Phour; |
|
// Длительность пары в часах |
|
int Pmin; |
|
// Длительность пары в минутах |
|
int interval; |
|
// Длительность перерыва в минутах |
|
int hh, mm; |
|
|
|
int n; |
|
|
// Количество пар |
cout << "Введите время начала первой пары: "; |
|||
cin >> hh >> mm; |
|
|
|
Pair.Set(hh, mm); |
|
// Установка времени в структуре Pair |
|
cout << "Введите длительность пары в часах и минутах: "; |
|||
cin >> Phour >> Pmin; |
|
|
|
cout << "Введите длительность перерыва в минутах: "; |
|||
cin >> interval; |
|
|
|
cout << "Введите количество пар: "; |
|||
cin>> n; |
|
|
|
cout << "Начало Конец" << endl; |
// Заголовок таблицы |
||
for(int i = 0; i < n; i++){ |
|
|
|
Pair.Print(); |
|
// Печать времени начала пары |
|
Pair.AddHour(Phour); Pair.AddMin(Pmin); //Расчет конца пары |
|||
Pair.Print(); cout << endl; |
// Печать времени конца пары |
||
Pair.AddMin(interval); |
|
// Расчет начала следующей пары |
|
} |
|
|
|
getch(); |
|
|
|
} |
|
|
|
Вызов функции-члена структуры производится так же, как доступ к обычному члену структуры с помощью оператора точка (.).
Программа выводит:
Введите время начала первой пары: 8 0 Введите длительность пары в часах и минутах: 1 30 Введите длительность перерыва в минутах: 10 Введите количество пар: 6 Начало Конец 08:00 09:30 09:40 11:10 11:20 12:50 13:00 14:30 14:40 16:10 16:20 17:50
15.2. Встроенные функции
Функции, определенные внутри структуры или класса (о классах речь пойдет ниже), являются встроенными или inline.
Классы 203
В точках вызова обычных функций компилятор помещает команды копирования аргументов в локальные переменные и команду передачи управления на код функции. Сам код обычных функций существует в памяти в единственном экземпляре. В отличие от обычных функций, полный код встроенных функций вставляется в каждую точку их вызова, благодаря чему не нужны команды передачи управления, что ведет к экономии времени, однако может увеличить общий размер рабочей программы.
Учитывая сказанное, можно рекомендовать делать встроенными короткие функции, которые часто вызываются, что может привести к ускорению работы программы.
Можно явно указывать, что функция является встроенной. Для этого используется ключевое слово inline. Например, внутри структуры Time функцию Set можно объявить в виде:
void Set(int hh, int mm); |
// Установка времени |
Указать на то, чтобы эта функция была встроенной, можно при ее определении вне структуры:
inline void Time::Set(int hh, int mm) |
// Установка времени |
{ |
|
h = hh; m = mm; |
|
} |
|
Есть ограничения на операторы, которые могут входить во встроенные функции. Они не должны содержать условный оператор if, операторы цикла. Функции, содержащие такие операторы, будут обычными, несмотря на указание сделать их встроенными, а компилятор выдаст предупреждение.
15.3. Классы. Скрытие данных
Так как данные, хранящиеся в структуре, открыты, они могут изменяться в любой точке программы, что может привести к ошибкам, которые трудно обнаружить. Для повышения надежности программ желательно ограничить доступ к данным, чтобы они могли изменяться только небольшим числом функций. Данные скрываются с помощью классов, которые похожи на структуры, но определяются с использованием ключевого слова class.
Программа 42. Класс дат
Разработаем класс для моделирования календарных дат.
// Файл DateCl_1.cpp class Date{
204 |
15 |
|
int d, m, y; |
// День, месяц и год |
|
public: |
|
// Раздел открытых членов |
void Init_Date(int dd, int mm, int yy) |
// Инициализация даты |
|
{ |
|
// Реализация функции |
d = dd; m = mm; y = yy; |
// внутри класса |
|
} |
|
|
void Add_Year(int n); |
// Добавить к дате n лет |
|
void Print(); |
|
|
}; |
|
|
Метка public разделяет тело класса на две части: закрытую и открытую. Здесь закрытыми членами являются d, m и y. Члены класса, расположенные после public, являются открытыми, они образуют
открытый интерфейс класса.
Структура – это класс, все члены которого открыты по умолчанию. Функции-члены класса определяются так же, как функции-члены
структуры:
// Продолжение файла DateCl_1.cpp
#include <iostream.h> void Date::Print()
{
cout << d << ’.’ << m << ’.’ << y;
}
Включим в состав программы вспомогательную функцию для проверки, является или нет год високосным:
//Продолжение файла DateCl_1.cpp
//leap: возвращает 1, если год year високосный и 0, если нет int leap(int year)
{
return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
}
При реализации функции увеличения даты надо учесть 29 февраля високосного года. Если исходная дата приходится на 29 февраля високосного года, а через n лет год будет невисокосный, то будем считать, что спустя n лет после исходной даты будет 1 марта.
// Продолжение файла DateCl_1.cpp |
|
void Date::Add_Year(int n) |
|
{ |
|
if(m == 2 && d == 29 && leap(y + n) != 1){ |
// Через n лет после |
m = 3; |
// 29 февраля будет |
d = 1; |
// 1 марта невисокосного |
Классы 205
} |
// года |
y += n; |
|
}
Функции, не являющиеся членами класса, не могут осуществлять непосредственный доступ к закрытым членам, например,
void backday(Date& td) |
|
{ |
|
td.d--; |
// Ошибка, Date::d является закрытой |
} |
|
Ограничение доступа к данным имеет следующие преимущества: так как данные могут изменяться только функциями-членами, легче
локализовать ошибку; потенциальному пользователю класса проще освоить работу с ним,
так как достаточно изучить только открытые функции-члены класса, не изучая детали реализации.
Используем класс Date в следующей программе:
// Продолжение файла DateCl_1.cpp |
|
#include <conio.h> |
|
int main() |
|
{ |
|
Date Studies; |
// Переменная типа Date |
Studies.Init_Date(1, 9, 2005); |
// Инициализация переменной |
cout << ”Исходная дата: ”; Studies.Print(); cout << endl; |
|
Studies.Add_Year(5); |
// Увеличение даты на 5 лет |
cout << ”Через 5 лет: ”; Studies.Print(); cout << endl; |
|
Date D; |
// Еще переменная типа Date |
D.Init_Date(29, 2, 2000); |
|
cout << ”Интересная дата: ”; D.Print(); cout << endl; D.Add_Year(6);
cout << ”Через 6 лет: ”; D.Print(); cout << endl; getch();
return 0;
}
Программа выдаст:
Исходная дата: 1.9.2005 Через 5 лет: 1.9.2010 Интересная дата: 29.2.2000 Через 6 лет: 1.3.2006