суббота, 5 декабря 2009 г.

7.3. Композиция: классы как элементы других классов

Поскольку объекту класса AlarmClock необходимо знать, когда предпо­лагается подача сигнала тревоги, то почему бы не включить объект Time как элемент объекта AlarmClock? Такая возможность называется компози­цией. Класс может включать в себя объекты других классов в качестве эле­ментов.
Замечание по технике программирования 7.4
Одним из способов повторного использования программного обеспечения является
композиция, когда класс включает в себя объекты других классов в качестве эле­ментов.
Когда объект входит в область действия, автоматически вызывается его конструктор и нам надо указать, как аргументы передаются конструкторам объектов-элементов. Объекты-элементы создаются в том порядке, в котором они объявлены (а не в том порядке, в котором они перечислены в списке инициализаторов элементов конструктора), и до того, как будут созданы объ­екты включающего их класса.
Программа на рис. 7.4 использует классы Employee и Date для демон­страции объектов как элементов других объектов. Класс Employee содержит закрытые данные-элементы lastName, firstName, birthDate и hireDate. Эле­менты birthDate и hireDate являются объектами класса Date, который со­держит закрытые данные-элементы month, day и year. Программа создает объект Employee, задает начальные значения его данным-элементам и ото­бражает их на экране. Приведем синтаксис заголовка функции в описании конструктора Employee:
Employee::Employee (char *fname, char *lname,
int bmonth, int bday, int byear, int hmonth, int hday, int hyear) : birthDate(bmonth, bday, byear), hireDay(hmonth, hday, hyear)
Этот конструктор принимает восемь аргументов (fname, lname, bmonth, bday, byear, hmonth, hday и hyear). Двоеточие в заголовке отделяет иници­ализаторы элементов от списка параметров. Инициализаторы элементов ука- зывают, что аргументы Employee передаются конструкторам объектов-эле­ментов. В частности, bmonth, bday и byear передаются конструктору birth- Date, a hmonth, hday и hyearконструктору hirehDate. Инициализаторы элементов в списке разделяются запятыми.
Объекты-элементы не нуждаются в задании начальных значений посред­ством инициализаторов элементов. Если инициализаторы элементов не за­даны, конструктор с умолчанием объекта-элемента будет вызван автомати­чески. Значения, если они были установленные конструктором с умолчанием, могут быть затем изменены с помощью функций записи «set».
Типичная ошибка программирования 7.6
Не предусмотрен конструктор с умолчанием для объекта-элемента, когда для этого объекта элемента не задан инициализатор элементов. Это может привести к тому, что объект-элемент не будет инициализирован.
Совет по повышению эффективности 7.1
Инициализируйте объекты-элементы явно с помощью инициализаторов элементов. Это исключает накладные расходы связанные с повторной инициализацией объек- тов-элементов: первой при вызове конструктора с умолчанием объекта-элемента и второй при задании начальных значений объекта-элемента с помощью функции записи «set».
// DATE1.H
// Объявление класса Date.
// Функции-элементы определены в DATE1.CPP #ifndef DATE1_H
#define DATE1_H
class Date { public:
Date(int = 1,  int = 1, int = 1900); //конструктор по умолчанию
void print ()          const; // печать данных в формате
// месяц/день/год
private:
int month;                          // 1-12
int day;                // 1-31 в зависимости от месяца
int year;                        // любой год
// функция утилита для проверки соответствия дня месяцу и году int checkDay(int); } ;
#endif
Рис. 7.4. Использование инициализаторов объектов-элементов (часть 1 из 5)

// DATE1.CPP
// Определения функций-элементов класса Date.
#include
#include "datel.h"
// Конструктор: поддержка соответствующего значения месяца;
// вызов функции-утилиты checkDay для поддержки соответствующего
// значения дня.
Date::Date(int mn, int dy, int yr)
{
if (mn > 0 && mn <= 12)           // проверка месяца
month = mn; else {
month = 1 ;
cout « "Месяц " « mn
<< " неправильный. Установлен месяц 1." « endl;
}

year = yr;
day = checkDay(dy);
// можно было бы тоже проверить //проверка дня

cout « "Конструктор объекта Date print (); cout << endl;
}
// Функция-утилита для поддержки соответствующего //значения дня в зависимости от месяца и года.
int Date::checkDay(int testDay) {
static int daysPerMonth[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
if (testDay > 0 && testDay <= daysPerMonth[month]) return testDay;

// Февраль: проверка високосного года
100 != 0)))
if (month == 2 && testDay == 29 &&
(year % 400 == 0 || (year % 4 == 0 && year return testDay;

cout « "День " « testDay
« " неправильный. Установлен день 1." « endl;

return 1;
// если неверное значение, объект остается // в непротиворечивом состоянии

}
// Печать объекта Date в форме месяц/день/год void Date::print() const
{ cout « month « '/' « day « '/' « year;}

// EMPLYl.H
// Объявление класса Employee.
// Функции-элементы определены в EMPLY1.CPP
tifndef EMPLY1_H
#define EMPLY1_H
#include "datel.h"
class Employee { public:
Employee(char *, char *, int, int, int, int, int, int); void print() const; private:
char lastName[25]; char firstName[25]; Date birthDate; Date hireDate;
#endif
Рис. 7.4. Использование инициализаторов объектов-элементов (часть 3 из 5) // EMPLY1.СРР
// Описания функций-элементов класса Employee.
#include ciostream.h>
#include
finclude "emplyl.h"
#include "datel.h"
Employee::Employee (char *fname, char *lname, int bmonth, int bday, int byear, int hmonth, int hday, int hyear) : birthDate(bmonth, bday, byear), hireDate(hmonth, hday, hyear)
{
// копирование fname в firstName и проверка их совпадения
int length = strlen(fname);
length = length < 25 ? length : 24;
strncpy(firstName, fname, length);
firstName[length] = ' \0';
// копирование lname в lastName и проверка их совпадения
length = strlen(lname);
length = length < 25 ? length : 24;
strncpy(lastName, lname, 24);
lastName[length] = '\0';
cout << "Конструктор объекта Employee: "
« firstName « ' ' « lastName « endl;
void Employee::print() const {
cout « lastName « ", " « firstName « endl « "Нанят: ";
hireDate.print();
cout << " День рождения: ";
birthDate.print();
cout << endl;
■ }
Я 11 FIG7_4.CPP
Hj // Демонстрация объекта с объектом-элементом. ИИ iinclude iinclude "emplyl.h" main()
■s--^ Employee е("Боб", "Джон", 7, 24, 49, 3, 12, 88); cout << endl; e .print () ;
**

cout << endl << "Проверка конструктора Date " << "с неправильными значениями:" << endl; Date d(14, 35, 94);                       //Неправильные значения Date
return 0;
}
Конструктор объекта Date 7/24/49 г Конструктор объекта Date 3/12/88
Конструктор объекта Employee: Боб Джон
Джон, Боб
Нанят: 3/12/88 День рождения: 7/24/49
Проверка конструктора Date с неправильными значениями: Месяц 14 неправильный. Установлен месяц 1. День 35 неправильный. Установлен день 1. Конструктор объекта Date 1/1/94
Рис. 7.4. Использование инициализаторов объектов-элементов (часть 5 из 5)

Комментариев нет:

Отправить комментарий