Объектно-ориентированные системы программирования

Рассмотрим проблемы реализации проекта, разработанного с использованием методологии OMT, в системах программирования объектно-ориентированных языков. В качестве примеров таких систем программирования будут рассмотрены системы программирования известных объектно-ориентированных языков C++, Eiffel и Smalltalk.

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

Изложение будет вестись на примере реализации графического редактора, часть объектной модели которого представлена на рисунке 5.1.

Объектно-ориентированные системы программирования - student2.ru

Рис. 5.1. Часть объектной модели графического редактора

Редактор поддерживает манипулирование рекурсивными группами графических объектов, составленных из прямоугольников и овалов (в частности, кругов); при этом определена операция «сгруппировать», которая превращает группу объектов в единый объект (всё это очень похоже на графическую подсистему редактора Microsoft Word).

5.3. Реализация на языке C++

Язык C++ является наиболее распространённым объектно-ориен-тированным языком программирования. Поэтому рассмотрение вопросов реализации начнём с этого языка. Поскольку язык C++ хорошо известен и достаточно широко распространён (это один из самых популярных языков программирования), здесь приводится лишь краткий обзор некоторых свойств и конструкций этого языка. В настоящее время издано огромное количество учебных пособий, справочников и других руководств по языку C++. Одним из наиболее полных, изданных на русском языке, является книга Ирэ Пол. Объектно-ориентированное программирование с использованием C++. // DiaSoft Ltd., Киев – 1995.

Реализация классов

Реализация прикладной программной системы, спроектированной с помощью объектно-ориентированной методологии (например, методологии OMT), на языке C++ начинается с определения классов, разработанных на этапе проектирования, на этом языке. При этом желательно сохранение имён и, по возможности, других обозначений, введённых на этапе проектирования. Рассмотрим в качестве примера, как реализовать на языке C++ класс Window, показанный на рисунке 5.1. Отметим, что реализация класса на языке C++ содержательно мало отличается от его представления в объектной модели OMT.

class Window{public:// конструкторWindow (Length x0, Length y0, Length width, Length height);// деструктор~Window ();// методыvoid add_box (Length x, Length y, Length width, Length height);void add_circle (Length x, Length y, Length radius);void clear_selections ();void cut_selections ();Group* group_selections ();void move_selections (Length deltax, Length deltay);void redraw_all ();void select_item (Length x, Length y);void ungroup_selections ();private:Length xmin;Length ymin;Length xmax;Length ymax;void add_to_selections (Shape* shape);};

В определении класса на языке C++ и атрибуты, и методы называются членами этого класса; их определения могут следовать в тексте определения класса в произвольном порядке. Члены класса могут быть общедоступными (public), или приватными (private); вне класса определён доступ только к его общедоступным членам, а приватные члены доступны только методам своего класса. В рассматриваемом примере все атрибуты являются приватными, а все методы (кроме метода add_to_selections) – общедоступными, так что прочитать или изменить значение каждого атрибута можно только с помощью соответствующего метода; это рекомендуемая, хотя и не обязательная дисциплина программирования на языке C++ (определение всех атрибутов класса как приватных называется инкапсуляцией данных).

Тип Length должен быть определён пользователем (обычно такие определения делаются в одном из файлов-заголовков, вставляемых в программу по #include). Для определения типа используется оператор typedef. Например:

typedef float Length;

или

typedef int Length;

Порождение объектов

В каждом классе языка C++ могут быть определены специальные методы (один или несколько), обращение к которым приводит к порождению нового объекта этого класса. Такие методы называются конструкторами. Конструкторы могут иметь параметры, что позволяет определить начальное состояние объекта при его порождении. Конструкторы имеют то же имя, что и имя класса, в котором они определены, так что если класс имеет несколько конструкторов, то они должны различаться числом и типом своих параметров. В качестве примера рассмотрим конструктор класса Window (рис. 5.1):

Window::Window (Length x0, Length y0,Length width, Length height){xmin = x0; ymin = y0;xmax = x0 + width; ymax = y0 + height;}

При обращении к этому конструктору порождается новое окно с координатами нижнего левого угла (x0,y0), шириной width и высотой height. Наряду с рассмотренным в этом классе могут быть определены и другие конструкторы:

Window (Length x0, Length y0);//берутся стандартные размеры окна

Window (); //берутся стандартные размеры и положение окна.

В языке C++ поддерживается три вида выделения памяти для размещения объектов: в фиксированной глобальной памяти (статическая память, static), в системном стеке (автоматическая память, automatic), в «куче» (динамическая память, dynamtic).

Чтобы разместить объект в статической памяти, достаточно либо объявить его вне какой-либо функции, либо при его объявлении указать ключевое слово static. Статическая память выделяется компилятором во время компиляции программы и не меняется во время её выполнения. Конструктор можно использовать для инициализации объектов, размещаемых в статической памяти (для выделения статической памяти под объект без его инициализации достаточно просто объявить его).

Объявление

Window main_window = Window(0.0, 0.0, 8.5, 11.0)

определяет статический объект main_window (основное окно), проинициализированный значениями параметров конструктора.

Локальные объекты, объявляемые внутри функций, размещаются в автоматической памяти (системном стеке). Их тоже можно инициализировать с помощью конструктора. Наконец, обращение к конструктору в операторе new в процессе выполнения программы порождает объект, размещаемый в динамической памяти. Например:

Window *window = new Window (0.0, 0.0, 8.5, 11.0);

При этом выражение new Window (0.0, 0.0, 8.5, 11.0) имеет своим значением указатель на порождённый динамический объект.

Для терминации объектов можно использовать специальный метод, являющийся одним из членов класса и называемый деструктором. Как и конструктор, он имеет то же имя, что и имя класса, в котором он определён, но первым символом имени деструктора является тильда (~):

Window::~Window (); {

//убрать окно и перекрасить освободившуюся область

}

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

delete window;

Необходимость использования операции delete связана с тем, что в системе C++ не производится сборки мусора, и программист должен сам заботиться об освобождении динамической памяти от ненужных объектов, чтобы избежать её переполнения (в более современной системе программирования Java обеспечивается автоматическая сборка мусора, что существенно упрощает программирование).

Вызов операций

В языке C++ операция (метод) определяется как один из членов класса. При вызове операции используются те же обозначения, что и при обращении к атрибутам: операция выбора члена «->» применяется к соответствующему указателю:

Shape* shape;

shape->move(dx,dy);

Параметрами операции могут быть значения одного из встроенных типов (int, float, char и т.п.), либо значения типов, определённых с помощью typedef, либо объекты некоторых классов, либо указатели переменных и констант перечисленных типов, либо указатели объектов.

Имя атрибута или операции, используемое в качестве идентификатора в реализации метода, неявно ссылается на соответствующие члены объекта, к которому применяется операция. В следующем примере x и y являются атрибутами объекта класса Shape, к которому будет применена операция move:

void Shape::move (Length deltax, Length deltay)

{

x = x + deltax;

y = y + deltay;

}

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

void Shape::move (Length deltax, Length deltay)

{

this->x = this->x + deltax;

this->y = this->y + deltay;

}

Ссылка на любой другой объект в описании операции должна обязательно быть квалифицированной (содержать указатель соответствующего объекта):

window->xmin = x1;

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