- •Предисловие
- •Глава 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. Стандартная библиотека шаблонов
- •Литература
- •Предметный указатель
210 15
Заметим, что в различных реализациях размер целых типов может различаться, конкретный размер любого типа можно узнать с помощью оператора sizeof.
Есть возможность иметь в одном экземпляре на весь класс не только функции-члены, но и переменные-члены класса. Это реализуется с помощью статических членов.
Изменим класс Date, предусмотрев в нем возможность расчета дня недели для любой даты. Для этого нужно задать некоторую начальную дату и ее день недели. Эти данные включим в класс как статические члены.
15.6. Друзья класса
Закрытые члены класса недоступны для посторонних функций, но иногда требуется открыть доступ к ним для функций, которые не являются членами класса. Такие функции надо объявить в классе с ключевым словом friend (друг). В следующей программе это функция:
bool leapyear(Date dt){ return leap(dt.y); }
которая обращается к закрытому свойству y даты dt и передает его значение функции leap. Для високосного года leap возвратит 1, а leapyear – true, для невисокосного leap возвратит 0, а leapyear, соответственно, false.
Программа 45. Статические члены и друзья класса
Объявим класс дат в следующем виде:
// Файл DateCl_4.cpp |
|
class Date{ |
|
int d, m, y; |
// День, месяц и год |
static int d0, m0, y0; |
// Начальная дата |
static int dw0; |
// День недели начальной даты, |
public: |
// 1 - понедельник, 2 - вторник,... |
|
|
Date(int = 0, int = 0, int = 0); |
// Конструктор |
void Print(); |
|
// Функция установки начальной даты
static void SetInitialDate(int di, int mi, int yi, int dwi)
{
d0 = di; m0 = mi; y0 = yi; dw0 = dwi;
} |
|
int DayOfYear(); |
// Номер дня в году |
int NumberDayOfWeek(); |
// Номер дня недели |
|
Классы 211 |
friend bool leapyear(Date ); |
// Объявление функции-друга |
};
Из программы 43 вставляем конструктор класса, функцию Date::Print(), таблицу дней в месяцах daytab и функцию leap().
Функция DayOfYear() возвращает номер дня в году. Например, 28 февраля – это 59-й день года, а 1 марта, это 60-й день невисокосного и 61-й день високосного года.
int Date::DayOfYear() |
// Возвращает номер дня в году |
{ |
|
int days = d; |
// Количество дней от начала месяца |
int lp = leap(y); |
// Признак високосности года |
for(int i = 1; i < m; i++) |
|
days += daytab[lp][i]; |
|
return days; |
|
} |
|
Функция NumberDayOfWeek() возвращает номер дня недели для произвольной даты. Считаем, что понедельник – это 1-й день, вторник – второй, …, воскресенье – 7-й. Алгоритм расчета состоит в следующем. Находится число дней, прошедших от понедельника той недели, на которую приходится начальная дата. Эта величина складывается из числа дней, прошедших до конца начального года, числа дней в целых годах, прошедших между начальной и конечной датами и числом дней, прошедших от начала года до заданной даты. Находится остаток от деления найденного числа дней на 7. Если остаток – 0, значит, заданная дата приходится на понедельник. Чтобы получить номер дня, к остатку прибавляется 1.
int Date::NumberDayOfWeek() |
// Возвращает номер дня недели |
{ |
// Понедельник - 1 |
Date dti(d0, m0, y0); |
// Начальная дата формируется по |
|
// статическим членам класса |
long days = dw0 - 1; |
// Количество дней, прошедших от |
|
// понедельника начальной недели |
days += 365 + leap(y0) - dti.DayOfYear(); // Учет дней в начальном году
for(int i = y0 + 1; i < y ; i++) |
// Учет дней |
days += 365 + leap(i); |
// в промежуточных годах |
days += DayOfYear(); |
// Учет дней в заданном году |
return days % 7 + 1; |
|
} |
|
Внутри класса статические члены только объявляются, при этом память под них не выделяется, поэтому статические члены следует
212 15
определить вне класса, чтобы под них была выделена память. При определении следует указывать имя класса.
// Определение статических членов класса int Date::d0, Date::m0, Date::y0, Date::dw0;
Начальная дата устанавливается с помощью вызова статической функции SetInitialDate. В качестве квалификатора имени статической функции можно указываться имя класса, вместо имени объекта класса, как это делается для обычной функции.
// Определение функции-друга
bool leapyear(Date dt){ return leap(dt.y); }
Внутри главной функции создается массив строк с названиями дней недели, из которого по номеру дня недели выбирается нужное название.
#include <conio.h> int main()
{
char* DayWeek[7] = { "Понедельник", "Вторник", "Среда", "Четверг", "Пятница", "Суббота", "Воскресенье"
// 31 декабря 1599 г. // была пятница
Date Today; // Использование конструктора по умолчанию, сегодня
cout << "\nСегодня "; Today.Print(); |
// Вывод даты |
// Вывод дня недели |
|
cout << ", "<< DayWeek[Today.NumberDayOfWeek() - 1]; cout << ”\n Идет високосный год: ” << leapyear(Today); getch();
return 0;
}
Программа выдает следующее:
Сегодня 25.11.2006, Суббота Идет високосный год: 0
Спомощью календаря убеждаемся в правильности результата.
15.7.Копирование объектов класса
Допустимы инициализация объекта другим объектом того же класса и присваивание объектов. При выполнении инициализации и присваивания происходит почленное копирование. В следующей
Классы 213
программе на примере класса Date демонстрируются инициализация и копирование объектов.
Программа 46. Копирование объектов
//Файл DateCl_5.cpp
//Здесь нужно поместить программу 43 за исключением функции main
int main()
{
Date Today; // Today инициализируется конструктором по умолчанию
Date Tomorrow = Today; |
// Tomorrow инициализируется датой Today |
Tomorrow.Add_Day(); |
// Увеличение даты на 1 день |
cout << "\nСегодня: "; Today.Print(); |
|
cout << "\nЗавтра: "; Tomorrow.Print(); |
|
Today = Tomorrow; |
// Присваивание дат |
cout << "\nToday: "; Today.Print(); getch();
return 0;
}
Программа напечатает:
Сегодня: 5.4.2006 Завтра: 6.4.2006 Today: 6.4.2006
Инициализация производится инструкциями вида:
Date Tomorrow = Today;
Инициализация выполняется на этапе компиляции и состоит в том, что под объект выделяется память, и в эту память заносятся задаваемые начальные значения. В результате инициализации Tomorrow становится копией Today, так как инициализация производится почленным копированием.
Присваивание вида:
Today = Tomorrow;
производится на этапе выполнения программы. При присваивании также производится почленное копирование, поэтому Today становится копией Tomorrow.
15.8. Управление доступом
Члены класса могут быть закрытыми (private), открытыми (public) и защищенными (protected). Защищенные члены являются закрытыми, но
214 15
доступными в классах, производных от данного класса. (Создание производных классов называется наследованием, см.§20.3).
Структуры и классы
По определению, структура есть класс, все члены которого по умолчанию являются открытыми, то есть
struct S{
…
};
эквивалентно
class S{ public:
…
};
После ключевого слова public перечисляются открытые члены.
С помощью ключевого слова private можно закрыть часть членов структуры:
struct S{ private:
//Закрытые члены структуры
…
public:
//Открытые члены структуры
…
};
Разделов public и private может быть несколько, они могут располагаться в любой последовательности.
Правила доступа
Действуют следующие правила доступа к членам класса:
∙К закрытым (private) членам класса имеют доступ только методы класса и функции-друзья класса.
∙К защищенным (protected) членам имеют доступ методы и друзья данного класса и методы и друзья классов, производных от него.
∙К открытым (public) членам имеет доступ любая функция.