
-
Лабораторная работа №1 создание классов
Цель работы: Получить практические навыки проектирования и реализации классов
-
Теоретические сведения
-
Классы
Объект — это совокупность отдельных информационных элементов и функций, которые им оперируют. Объект состоит из следующих трех частей:
-
имя объекта;
-
состояние (переменные состояния);
-
методы (операции).
Объект ООП — это совокупность переменных состояния и связанных с ними методов (операций). Эти методы определяют как объект взаимодействует с окружающим миром.
Возможность управлять состояниями объекта посредством вызова методов в итоге и определяет поведение объекта. Эту совокупность методов часто называют интерфейсом объекта.
Объектно — ориентированное программирование — это программирование, сфокусированное на данных, причем данные и поведение неразрывно связаны. Вместе данные и поведение представляют собой класс, а объекты являются экземплярами класса. ООП рассматривает вычисления как моделирование поведения. Например, многочлен имеет область значений, и она может изменяться такими операциями, как сложение и умножение многочленов.
Класс (class) — это группа данных и методов (функций) для работы с этими данными.
Объект (object) — это конкретная реализация, экземпляр класса. В программировании отношения объекта и класса можно сравнить с описанием переменной, где сама переменная (объект) является экземпляром какого — либо типа данных (класса).
Обычно, если объекты соответствуют конкретным сущностям реального мира, то классы являются некими абстракциями, выступающими в роли понятий. Для формирования какого—либо реального объекта необходимо иметь шаблон, на основании которого и строится создаваемый объект. При рассмотрении основ ООП очень часто смешивают понятия объекта и класса. Дело в том, что класс — это некоторое абстрактное понятие. Для проведения аналогий или приведения примеров оно не очень подходит. Намного проще приводить примеры, основываясь на объектах из реального мира, а не на абстрактных понятиях. Скажем так: объект — это физическая реализация класса.
Методы (methods) — это функции, принадлежащие классу.
Сообщение (message) — это практически тоже самое, что и вызов функций в обычном программировании. В ООП обычно употребляется выражение "послать сообщение" какому-либо объекту. Понятие "сообщение" в ООП можно объяснить с точки зрения основ ООП: мы не можем напрямую изменить состояние объекта и должны как бы послать сообщение объекту, что мы хотим так и так изменить его состояние. Объект сам меняет свое состояние, а мы только его просим об этом посылая сообщения
Пример
Простейшее описание класса и создание его экземпляра. В данном примере мы описываем пустой класс, представляющий будущий игровой мир и в теле программы создаём единственный экземпляр мира.
class
CWorld
{
}int
main ()
{
CWorld world;
}
Рисунок 1 – Простейшее описание класса
-
О компиляции
Прежде всего, программист с помощью того или иного текстового редактора готовит файлы исходного кода на C/C++. После этого происходит построение программы, в котором можно выделить такие этапы:
-
Компиляцию исходных файлов в файлы объектного кода (с расширением .obj).
-
Компоновку объектных файлов с присоединением необходимых библиотек (в том числе, возможно, динамических), в результате чего получается уже машинный код.
-
Компоновку ресурсов (ресурсы включают в себя битовые матрицы, курсоры, строковые таблицы, пиктограммы и т.п.). Это завершающий этап, на котором формируется конечный ехе-файл, запускаемый на выполнение.
Компилятор C/C++ генерирует стандартные объектные файлы с расширением .obj. (Их формат определен фирмой Intel и не зависит от конкретной операционной системы.) Файлы эти содержат машинный код, который снабжен дополнительной информацией, позволяющий компоновщику разрешать ссылки между объектными модулями. Так, в начале файла формируются две таблицы: таблица глобальных символов (это имена объектов, определяемых в данном файле, на которые могут ссылаться другие модули программы) и таблица внешних ссылок (имена объектов в других файлах, к которым обращается данный модуль). Пользуясь информацией этих таблиц, компоновщик модифицирует код, подставляя в него соответствующие адреса.
Проблема состоит в том, что в объектном файле отсутствует информация, которая позволяла бы проверить корректность вызова процедуры (т.е. количество и тип ее параметров), находящейся в другом файле. Ведь компилятор обрабатывает файлы исходного кода по отдельности.
C/C++ был задуман как максимально универсальный язык, и потому он не может использовать нестандартный формат объектных файлов. Это сделало бы невозможным, например, создание файлов подпрограмм, которые могли бы включаться в программы, написанные на других языках. Возможность раздельной компиляции обеспечивается в C/C++ применением заголовочных файлов, присоединяемых к компилируемым исходным файлам на этапе препроцессорной обработки. Заголовки содержат прототипы функций, объявления типов и другую информацию, необходимую для раздельной компиляции исходных модулей программы.
Заголовочные файлы (они имеют расширение .h или .hpp) подключаются к компилируемому файлу исходного кода (.с или .срр) с помощью директивы препроцессора #include, за которой следует имя заголовочного файла в кавычках или угловых скобках, например:
#include <stdlib.h>
include "myfile.h"
Препроцессор заменяет директиву #include содержимым указанного файла; после завершения препроцессорной обработки полученный текст передается компилятору, который транслирует его в объектный код.
Один и тот же заголовок можно подключать ко многим исходным файлам. Таким образом, отдельно компилируемые модули получают доступ к необходимой информации о процедурах и прочих элементах программы, определяемых в других модулях. Кроме того, это гарантирует, что размещенное в заголовочном файле объявление типа или функции будет одним и тем же во всех компилируемых файлах, и любые внесенные в него изменения будут автоматически воздействовать на все модули программы.
С практической точки зрения раздельная компиляция нужна для сокращения времени компиляции при внесении изменений в код какого-то класса. Раздельная компиляция подразумевает разделение прототипов классов и функций и их реализаций. Соответствие прототипов и реализаций происходит на этапе компоновки объектных файлов. Таким образом, если изменение затронуло реализацию группы классов, в перекомпиляции будут нуждаться только эти классы. Однако последующая компоновка и проверка зависимостей остаётся необходимой.
В С++ раздельная компиляция реализуется путём создания проекта, в который включаются файлы, содержащие реализацию. Обычно, эти файлы имеют расширение «.cpp». При перкомпиляции проекта компилятор проверяет изменения, которые произошли с файлами, включёнными в проект и производит соответствующую компиляцию. Заголовочные файлы (с расширением «.hpp» или «.h») в проект не включаются, но они должны быть включены в каждый файл реализации, в котором используется то, что описано в заголовочных файлах. Типичным примером может служить разделение прототипа класса и реализация его методов. Обычно прототип файла описывается в одноимённом с классом файле .hpp, реализация — в одноимённом файле .cpp. Следует помнить, что препроцессор не проверяет, сколько раз на этапе препроцессинга файл был включен в программу, поэтому необходимо вручную с помощью условных комментариев контролировать единственность включения (например, этого можно достичь, используя #ifndef - #define, как показано в примере ниже).
Пример. Описание класса CWorld в двух файлах для раздельной компиляции.
//Файл CWorld.hpp
#ifndef CWORLD_HPP
#define
CWORLD_HPP
#include
"CIObject.hpp"
#include"CPlayer.hpp"
#define
MAXOBJECTS 20
class
CWorld
{
private
:
unsignedlong
time,
// общемировое время
btime;// время последнего бонуса
protected
:
CIObject *objects[MAXOBJECTS];
int
objectsn;
CPlayer player;
public
:
CWorld();
~CWorld();
};#endif
Рисунок 2 – заголовочный файл класса CWorld
//Файл CWorld.cpp
#
ifndef
CWORLD
_
CPP
#
define
CWORLD
_
CPP
#
include
"
CIObject
.
hpp
"
#include
"
CPlayer
.
hpp
"
#include
"
CWorld
.
hpp
"
CWorld
::
CWorld
() :
player
(200,300, 0, 0)
// инициализация игрока
{objectsn
=0;
time
= 0;
btime
= 0;
}CWorld
::~
CWorld
()
{delete
[]
objects
;
}
}#
endif
Рисунок 3 – файл реализации класса CWorld