Программа 40. Время как структура

// Файл 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(); // Печать времени

};

В состав структуры 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()

{

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

Встроенные функции

Функции, определенные внутри структуры или класса (о классах речь пойдет ниже), являются встроенными или inline.

В точках вызова обычных функций компилятор помещает команды копирования аргументов в локальные переменные и команду передачи управления на код функции. Сам код обычных функций существует в памяти в единственном экземпляре. В отличие от обычных функций, полный код встроенных функций вставляется в каждую точку их вызова, благодаря чему не нужны команды передачи управления, что ведет к экономии времени, однако может увеличить общий размер рабочей программы.

Учитывая сказанное, можно рекомендовать делать встроенными короткие функции, которые часто вызываются, что может привести к ускорению работы программы.

Можно явно указывать, что функция является встроенной. Для этого используется ключевое слово inline. Например, внутри структуры Time функцию Set можно объявить в виде:

void Set(int hh, int mm); // Установка времени

Указать на то, чтобы эта функция была встроенной, можно при ее определении вне структуры:

inline void Time::Set(int hh, int mm) // Установка времени

{

h = hh; m = mm;

}

Есть ограничения на операторы, которые могут входить во встроенные функции. Они не должны содержать условный оператор if, операторы цикла. Функции, содержащие такие операторы, будут обычными, несмотря на указание сделать их встроенными, а компилятор выдаст предупреждение.

Классы. Скрытие данных

Так как данные, хранящиеся в структуре, открыты, они могут изменяться в любой точке программы, что может привести к ошибкам, которые трудно обнаружить. Для повышения надежности программ желательно ограничить доступ к данным, чтобы они могли изменяться только небольшим числом функций. Данные скрываются с помощью классов, которые похожи на структуры, но определяются с использованием ключевого слова class.

Программа 41. Класс дат

Разработаем класс для моделирования календарных дат.

// Файл DateCl_1.cpp

class Date{

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 марта невисокосного

} // года

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

Конструкторы

Для инициализации объектов класса создаются специальные функции-члены – конструкторы. Имя конструктора совпадает с именем класса. Конструктор не возвращает никакого значения, даже void. Если класс имеет конструктор, то конструктор вызывается автоматически при создании объекта класса, поэтому все объекты класса будут проинициализированы.

Дополним класс дат конструкторами:

class Date{

int d, m, y; // День, месяц и год

public:

Date(int, int, int); // Конструктор с параметрами (число, месяц, год)

Date(); // Конструктор без параметров (по умолчанию)

Date(int, int); // Конструктор, день, месяц, текущий год

};

Конструкторов может быть несколько, они различаются по правилам перегруженных функций, то есть по числу и типам аргументов. С целью уменьшения числа конструкторов можно использовать аргументы по умолчанию:

class Date{

int d, m, y; // День, месяц и год

public:

Date(int = 0, int = 0, int = 0); // Данный конструктор заменяет три

};

Наши рекомендации