Смекни!
smekni.com

Методические указания к курсу программирования для студентов физического факультета Сравнительное объектно-ориентированное проектирование (стр. 5 из 8)

· В описании

typedef bool __fastcall(__closure *OnMoveEvent)(TSprite* ,TPoint&); именем описываемого типа является OnMoveEvent. Сам тип является методом класса с двумя параметрами типа TSprite* и TPoint&, который возвращает тип bool. То, что OnMoveEvent именно метод класса, а не просто функция, отмечено модификатором __closure. Тип TPoint является стандартным и описан в библиотеке C++Builder. Знак & служит для описания «параметра по ссылке» – аналог служебного слова var в Delphi.

· Модификаторы доступа к членам класса в C имеют слегка иной смысл, нежели в Delphi. Все члены с модификатором private доступны только методам этого же класса вне зависимости от того, в каком модуле класс описан. Члены класса с модификатором protected – только методам своего класса и классов-наследников. В Delphi члены с модификаторами private и protected доступны всему коду того модуля, в котором описан класс. Однако в C++ существует способ сделать доступными защищенные (private и protected) члены класса другому классу. Для этого класс, методам которого разрешается доступ к защищенным членам, описывается как friend. Примером является декларация из описываемого кода friend class TSpriteList. Она говорит, что классу TSpriteList разрешается доступ ко всем без исключения членам класса TSprite.

· Обратите внимание на синтаксис описания абстрактного метода в C++ void __fastcall virtual PaintPicture()=0;

Реализация классов спрайтов

Ниже приведен полный код реализации классов спрайтов, описанных в хэдере. Комментарий к коду приводится непосредственно в тексте кода.

#include <vcl.h> //Модуль, несущий определения библиотеки VCL

/*Директива #pragma hdrstop означает окончание списка хэдеров,

компилируемых предварительно для использования в нескольких

файлах-исходниках одного проекта. В данном случае в этом списке

есть только файл vcl.h.

Директива #pragma hdrstop автоматически добавляется средой.*/

#pragma hdrstop

#include "uSprite.h" //хэдер нашего исходника

/*Директива #pragma package(smart_init) служит для «разумной»

последовательности в инициализации модулей при формировании

кода проекта. Она также автоматически добавляется средой

при создании нового модуля.*/

#pragma package(smart_init)

/*Далее располагается собственно авторский код.

Любой метод класса должен иметь в заголовке

имя класса, отделенного от имени самого метода

двойным двоеточием. В Delphi это была точка.*/

// Здесь реализуются методы класса TSpriteList.

// Конструктор инициализирует поля класса

__fastcall TSpriteList::TSpriteList(TControlCanvas* const canvas)

{

if (canvas) //Условие оператора if всегда пишется в скобках.

/* Проверку наличия не нулевого указателя можно проводить,

используя просто сам указатель, как в коде.

Это равносильно записи условия в виде (canvas!=NULL) –

указатель canvas не равен NULL*/

{

// служебное слово this в C имеет смысл self в Delphi – указатель на вызывающий объект

// вызов члена объекта, если объект задан своим указателем, происходит оператором ->

// оператор присвоения в С имеет вид =, а для сравнения используется двойной знак ==

this->canvas=canvas;

clientRect=canvas->Control->ClientRect;

canvasCopyMode=canvas->CopyMode;

list=new TList(); // Так создается экземпляр объекта. Здесь TList() – конструктор.

} else

/*Служебное слово throw используется для создания исключительной ситуации.

После этого нормальный ход программы прерывается.

Управление передается на ближайший блок catch.*/

throw Exception("Канва не задана!");

}

// Деструктор очищает список от спрайтов, восстанавливает свойства канвы

// и убирает сам экземпляр списка list

__fastcall TSpriteList::~TSpriteList()

{

Clear();

canvas->CopyMode=canvasCopyMode;

delete list; // Так вызывается деструктор объекта.

}

// Возвращает элемент списка спрайтов, отвечающий слою aZ,

// как указатель на объект типа TSprite

TSprite* __fastcall TSpriteList::GetItems(int aZ)

{

// служебное слово return вызывает выход из метода и возвращение значения функции

// выражение (TSprite*) означает преобразование типа указателя, полученного после

// вызова свойства list->Items[aZ], в указатель на TSprite

return (TSprite*)list->Items[aZ];

}

// Добавляет в список объект типа TSprite и возвращает указатель на добавленный объект

TSprite* __fastcall TSpriteList::AddSprite(TSprite* const sprite)

{

// двойной знак && есть операция логического умножения

if (sprite && Contains(sprite->SpriteRect,ClientRect))

{

sprite->spriteList=this;

sprite->z =list->Add(sprite);

count=list->Count;

return sprite;

} else return NULL;

}

// Перемещает спрайт с одной плоскости в другую (в смысле z-упорядочения)

void __fastcall TSpriteList::MoveSprite(int const fromZ, int const toZ)

{

if (fromZ != toZ && fromZ > -1 && fromZ < count &&

toZ > -1 && toZ < count)

{

//В языке C локальные переменные (как minZ здесь)

// могут быть описаны в любой точке кода

// Выражение вида a = b?c:d называется условным выражением.

// В нем переменной a присваивается значение c, если выполняется условие b,

// и значение d, если оно не выполняется

// int minZ = fromZ < toZ ? fromZ : toZ;

// В операторе цикла значение i в начале инициализируется,

// затем проверяется условие окончания цикла,

// выполняется оператор внутри цикла (если условие соблюдено),

// затем меняется значение параметра i.

// В данном случае оператор i-- означает уменьшение i на 1.

for (int i = count - 1; i >= minZ; i--)

if (Items[i]->Visible) Items[i]->Restore();

list->Move(fromZ,toZ);

for (int i = minZ; i < count; i++)

{

Items[i]->z = i;

if (Items[i]->Visible) Items[i]->Paint();

}

}

}

// Освобождает экземпляр объекта типа TSprite,

// находящийся в списке под номером aZ, и убирает указатель из списка

void __fastcall TSpriteList::DeleteSprite(int const aZ)

{

if (aZ<count && aZ>-1)

{

for (int i= count-1;i>=aZ;i--)

if (Items[i]->Visible) Items[i]->Restore();

delete Items[aZ];

list->Items[aZ]=NULL;

list->Delete(aZ);

count=list->Count;

for (int i=aZ;i<count;i++)

{

Items[i]->z--;

if (Items[i]->Visible) Items[i]->Paint();

}

}

}

// Очищает список от всех спрайтов

void __fastcall TSpriteList::Clear()

{

if (list && count > 0)

for (int i = count - 1; i > -1; i--) DeleteSprite(i);

};

// Реализация методов класса списка спрайтов со следом TTracedSpriteList

// Конструктор вызывает конструктор предка и инициализирует поле traceMap

// После имени конструктора через двоеточие вызывается конструктор предка TSpriteList.

__fastcall TTracedSpriteList::TTracedSpriteList(TControlCanvas* const canvas):

TSpriteList(canvas) // Вызов конструктора предка

{

traceMap.Length=ClientRect.Right-ClientRect.Left+1;

for (int i=0;i<=traceMap.High;i++)

traceMap[i].Length=ClientRect.Bottom-ClientRect.Top+1;

}

// Деструктор вызывает очистку списка от спрайтов и вызывает деструктор предка

__fastcall TTracedSpriteList::~TTracedSpriteList()

{

Clear();

}

// Удаляет спрайт слоя aZ из списка и удаляет сам спрайт

void __fastcall TTracedSpriteList::DeleteSprite(int const aZ)

{

((TTracedSprite*)Items[aZ])->TrPoints.Length=0;

TSpriteList::DeleteSprite(aZ); // Вызывается метод предка

}

// Очищает следы спрайтов и вызывает унаследованный метод очистки

void __fastcall TTracedSpriteList::Clear()

{

for (int i=traceMap.Low;i<= traceMap.High;i++)

for (int j=traceMap[i].Low;j<traceMap[i].High;j++)

traceMap[i][j]=false;

TSpriteList::Clear(); // Вызывается метод предка

}

// Реализация методов класса спрайт TSprite

// Конструктор инициализирует поля класса

__fastcall TSprite::TSprite(TRect const rect)

{

location=Point(rect.Left,rect.Top);

size.cx=rect.Width(); size.cy=rect.Height();

image=new Graphics::TBitmap();

image->Height=rect.Height();

image->Width =rect.Width();

z=-1;

}

// Деструктор уничтожает поле image

__fastcall TSprite::~TSprite()

{

delete image;

}

// Устанавливает новое значение поля visible и изображает или убирает спрайт с экрана

void __fastcall TSprite::SetVisible(bool const value)

{

if (value!=visible)

{

if (value)

{

BeginPaint();

Paint();

EndPaint();

} else

{

BeginPaint();

Restore();

EndPaint();

}

visible=value;

}

}

// Директива компилятору #define в данном случае вводит имя sprite

// для выражения ((TSprite*)(spriteList->Items[i])).

// Это укорачивает имя кода последующих методов

#define sprite ((TSprite*)(spriteList->Items[i]))

// Перемещает спрайт на вектор drift в плоскости изображения

bool __fastcall TSprite::Move(TSize const drift)

{

TPoint newPos=Point(location.x+drift.cx,location.y+drift.cy);

bool result=true;

// В этом месте вызывается обработчик события onMove, если он задан

if (onMove) result=onMove(this,newPos);

// Здесь используется то, что оператор присвоения в C возвращает присвоенное значение

// Переменная result приобретает новое значение и одновременно возвращает его как

// условие оператора if

if (result=result &&

Contains(Rect(newPos.x,newPos.y,newPos.x+size.cx,newPos.y+size.cy),

spriteList->ClientRect))

{

bool VisState=visible;

Visible=false;

location=newPos;

Visible=VisState;

}

return result;

}

// Перемещает спрайт в точку newPos

bool __fastcall TSprite::MoveTo(TPoint const newPos)

{

TSize s;

s.cx=newPos.x-location.x;s.cy=newPos.y-location.y;

return Move(s);

}

// Готовит изображение спрайта

void __fastcall TSprite::BeginPaint()

{

SetMask(Z);

for (int i=spriteList->Count-1;i>=Z+1;i--)

if (sprite->mask && sprite->visible) sprite->Restore();

}

// Устанавливает маску для спрайта с индексом anID (слой)

void __fastcall TSprite::SetMask(int const anID)

{

for (int i=anID+1;i<spriteList->Count;i++)

{

sprite->mask= sprite->Intersect(anID,i) || sprite->mask;

if (mask) SetMask(i);

}

}

// Завершает изображение спрайта