· В описании
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);
}
}
// Завершает изображение спрайта