Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лабораторная работа4.doc
Скачиваний:
3
Добавлен:
30.11.2018
Размер:
130.05 Кб
Скачать

Лабораторная работа № 4

Тема: Интерфейс и реализация класса. Принцип организации модульности при построении объектно-ориентированных программ

Цель: познакомиться с принципом организации модульности и научиться реализовывать принцип инкапсуляции и абстрагирования посредством модульности программного кода.

Теоретические сведения

Клaсс (class) – это определенный пользователем тип данных, который используется для описания абстрактного множества объектов, связанных обобщением структуры и поведения. В определении нового типа основная идея - отделить несущественные подробности реализации (например, формат данных, которые используются для хранения объекта типа) от тех качеств, которые существенны для его правильного использования (например, полный список функций, которые имеют доступ к данным). Такое разделение можно описать так, что работа со структурой данных и внутренними административными подпрограммами осуществляется через специальный интерфейс (каналируется).

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

Такие основные концепции ООП, как инкапсуляция, абстрагирование на техническом уровне достигается модульностью - разбиением программы на несколько файлов.

Вполне логично возникает вопрос: что именно поместить в один файл, что в другой?

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

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

Все нетривиальные программы собираются из нескольких раздельно компилируемых единиц (их принято называть просто файлами).

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

Рассматривая организацию данных Дата, мы замечаем, что объявление класса Дата целесообразно вынести в заголовочный файл Date .h.

#include<stdio.h>

#include<conio.h>

class Date

{

int d; // день

int m; // мiсяць

int y; // рiк

public:

void print();

Date(int dd,int mm,int yy);

int leapyear();

void add_day(int dd);

void add_month(int mm);

void add_year(int yy);

};

void Date::print()

/* виведення на екран дати */

{

printf("%d.%d.%d\n",d,m,y);

}

Date::Date(int dd,int mm,int yy)

/* iнiцiалiзацiя структури типу Date */

{

d=dd;

m=mm;

y=yy;

}

int Date::leapyear()

/* визначення, чи високосний рiк */

{

if ((y%4==0&&y%100!=0)||(y%400==0)) return 1;

else return 0;

}

void Date::add_year(int yy)

/* додати yy рокiв до дати */

{

y+=yy;

}

void Date::add_month(int mm)

/* додати mm мiсяцiв до дати */

{

m+=mm;

if (m>12)

{

y+=m/12;

m=m%12;

}

}

void Date::add_day(int dd)

/* додати dd днiв до дати */

{

int days[]={31,28,31,30,31,30,31,31,30,31,30,31};

d+=dd;

if (leapyear()) days[1]=29;

while ((d>days[m-1]))

{

if (leapyear()) days[1]=29;

else days[1]=28;

d-=days[m-1];

m++;

if (m>12)

{

y+=m/12;

m=m%12;

}

}

}

void main(void)

{

Date date1(14,02,2008),date2(1,1,2003), my_burthday (17,02,1985);

// мой день рождения

date1.print();

date2.print();

my_burthday.print();

date1.add_day(16);

date1.print();

date2.add_month(15);

date2.print();

date1.leapyear();}

При таком стиле использования заголовочных файлов .h файл и связанный с ним .c файл можно рассматривать как модуль, в котором .h файл задает интерфейс, а .c файл задает реализацию. Или вот фрагмент програмного кода:

Таблица символов не зависит от остальной части калькулятора за исключением использования функции ошибок. Это можно сделать явным:

//table.h: описания таблицы имен

struct name {

char* string;

name* next;

double value;

};

extern name* look(char* p, int ins = 0);

inline name* insert(char* s) { return look(s,1); }

//table.c: определения таблицы имен

#include "error.h"

#include

#include "table.h"

const TBLSZ = 23;

name* table[TBLSZ];

name* look(char* p; int ins) { /* ... */ }

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

Поэтому дальнейшее исследование модульности классов требует рассмотрение дополнительных моментов.

Любой глобальный объект, используемый в программе, должен быть определен, причем только один раз. Встроенные функции могут определяться несколько раз, если только все определения совпадают. Такое требование единственности или точного совпадения получило название правила одного определения (ПОО).