Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Tekhnologia_programmirovania.pdf
Скачиваний:
182
Добавлен:
08.04.2015
Размер:
1.76 Mб
Скачать

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;

 

}

 

Внутри класса статические члены только объявляются, при этом память под них не выделяется, поэтому статические члены следует

}; // Вызов статической функции класса
Date::SetInitialDate(31, 12, 1599, 5);

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) членам имеет доступ любая функция.