__property TSprite* Items[int Index]={read=GetItems};
// Конструктор
__fastcall TSpriteList(TControlCanvas* const);
// Деструктор
__fastcall virtual ~TSpriteList();
// Методы
TSprite* __fastcall AddSprite(TSprite* const);
void __fastcall MoveSprite(int const, int const);
void __fastcall virtual DeleteSprite(int const);
void __fastcall virtual Clear();
};
// Тип массива следов спрайтов на канве
typedef DynamicArray< DynamicArray < bool > > TTraceMap;
//TTracedSpriteList
class TTracedSpriteList:public TSpriteList
{
private:
// Поле
TTraceMap traceMap;
public:
// Свойство
__property TTraceMap TraceMap = {read=traceMap};
// Конструктор
__fastcall TTracedSpriteList(TControlCanvas* const);
// Деструктор
__fastcall ~TTracedSpriteList();
// Методы
void __fastcall virtual DeleteSprite(int const);
void __fastcall virtual Clear();
};
typedef bool __fastcall(__closure *OnMoveEvent)(TSprite* ,TPoint&);
//TSprite
class TSprite:public TObject
{
// Класс TSpriteList, объявленный friend, получает доступ
// к private и protected членам класса TSprite
friend class TSpriteList;
private:
// Поля
bool visible;
int z;
TSpriteList* spriteList;
OnMoveEvent onMove;
TSize size;
TPoint location;
Graphics::TBitmap* image;
bool mask;
// Методы
void __fastcall SetVisible(bool const);
TRect __fastcall GetSpriteRect();
void __fastcall BeginPaint();
void __fastcall EndPaint();
void __fastcall SetMask(int const);
bool __fastcall Intersect(int const,int const);
protected:
// Методы
void __fastcall virtual PaintPicture()=0;
void __fastcall virtual Restore();
void __fastcall virtual Paint();
public:
// Свойства
__property bool Visible={read=visible,write=SetVisible};
__property int Z={read=z};
__property TSpriteList* SpriteList={read=spriteList};
__property OnMoveEvent OnMove={read=onMove,write=onMove};
__property TSize Size={read=size};
__property TPoint Location={read=location};
__property TRect SpriteRect={read=GetSpriteRect};
// Конструктор
__fastcall TSprite(TRect const);
// Деструктор
__fastcall virtual ~TSprite();
// Методы
bool __fastcall virtual Move(TSize const);
bool __fastcall virtual MoveTo(TPoint const);
};
// Тип динамического массива точек со следами спрайта
typedef DynamicArray <TPoint> TTracePoints;
//TTracedSprite
class TTracedSprite:public TSprite
{
private:
// Поля
TTracePoints trPoints;
bool traced;
bool traceColored;
TColor traceColor;
TPoint center;
// Метод
void __fastcall SetTraceColor(TColor const);
public:
// Свойство
__property TTracePoints TrPoints={read=trPoints};
__property bool Traced={read=traced,write=traced};
__property TColor TraceColor={read=traceColor,write=SetTraceColor};
__property bool TraceColored={read=traceColored,write=traceColored};
__property TPoint Center={read=center};
// Конструктор
__fastcall TTracedSprite(TRect const);
// Деструктор
__fastcall ~TTracedSprite();
// Методы
bool __fastcall virtual Move(TSize const);
void __fastcall PutTrace();
};
const TColor DefaultColor=0xffffff;
//TEllipseSprite
class TEllipseSprite:public TTracedSprite
{
private:
// Поле
TColor color;
protected:
// Методы
void __fastcall virtual PaintPicture();
void __fastcall SetColor(TColor const);
public:
// Свойство
__property TColor Color={read=color, write=SetColor};
// Конструктор
__fastcall TEllipseSprite(TRect const);
};
bool Contains(TRect const source,TRect const dest)
{
return source.Left>=dest.Left && source.Top>=dest.Top &&
source.Right<=dest.Right && source.Bottom<=dest.Bottom;
}
#endif
Весь код хэдера заключен «в скобки» защитного блокиратора вида
#ifndef uSpriteH
#define uSpriteH
…
#endif
Это директивы компилятору, которые переводятся так
#ifndef uSpriteH – если не определен символ uSpriteH
#define uSpriteH – определи символ uSpriteH
#endif – заверши область действия директивы «если».
Таким образом, если перед началом компиляции модуля символ uSpriteH определен, то все, что находится дальше вплоть до директивы #endif , то есть все операторы модуля, компилироваться не будут. Символ uSpriteH определяется при первой компиляции, когда он еще не определен, поэтому все повторные компиляции модуля блокируются.
Рассмотрим отдельные фрагменты кода.
class TSprite;
//TSpriteList
class TSpriteList
{
private:
// Поля
int count;
TControlCanvas* canvas;
…
void __fastcall SetVisible(bool const);
TRect __fastcall GetSpriteRect();
…
__property int Count = {read=count};
…
__property TSprite* Items[int Index]={read=GetItems};
// Конструктор
__fastcall TSpriteList(TControlCanvas* const);
// Деструктор
__fastcall virtual ~TSpriteList();
TSprite* __fastcall AddSprite(TSprite* const);
…
}
Здесь
· В описании типов и переменных на языке C в начале указывается идентификатор типа или тип, а затем имя типа или переменной: class TSpriteList или int count.
· Описание членов класса заключается в фигурные скобки. Эти скобки в C играют также роль ограничителей begin, end в Delphi.
· В описании TControlCanvas* canvas; стоит звездочка *. Это описание в языке С означает, что поле canvas является ссылкой на объект класса TControlCanvas, т.е. просто целым числом, содержащим адрес объекта в памяти. Если звездочку опустить, то canvas будет описана как объект типа TControlCanvas «по значению», т.е. содержать в себе все поля объекта типа TControlCanvas. В языке C описание объекта по значению приводит к тому, что в месте описания происходит создание реального экземпляра объекта – вызывается его «конструктор по умолчанию» и все поля инициализируются.
· В языке C нет процедур, как в Delphi, - только функции. Те функции, которые не возвращают значений, имеют тип void. Они являются аналогами процедур в Delphi.
· В C++ Builder в описании всех методов классов участвует модификатор __fastcall. Его смысл - обеспечить компиляцию в наиболее быстрый способ вызова метода при выполнении кода.
· В языке C даже, если функция не имеет параметров, в ее описании должны стоять скобки как в GetSpriteRect().
· В отличие от Delphi транслятор с языка C различает прописные и строчные буквы. Поэтому принято давать одинаковые имена полям и соответствующим свойствам, но начинать имена полей со строчной буквы, а свойств – с прописной буквы. Сравните, к примеру, описания поля count и свойства Count.
· Обратите внимание на синтаксис описания свойств в C++ Builder.
· Конструктор в C++ отличается от других методов тем, что его имя совпадает с именем класса и что он не возвращает никакой тип, даже void.
· Имя деструктора также совпадает с именем класса, но перед именем дается знак отрицания ~. Как и констуктор, деструктор не возвращает какой-либо тип. Кроме того, деструктор не должен иметь параметров. Деструктор часто объявляется виртуальным. В этом случае деструкторы всех наследников автоматически становятся виртуальными.
· В C++ модификатор virtual у виртуальных методов не заменяется у наследников на override, а остается virtual.
· В реализации на C++ у метода AddSprite есть только один параметр – ссылка на объект класса TSprite. Поэтому при обращении к методу AddSprite объект спрайта должен быть уже создан. В C++ нет возможности вызвать конструктор объекта, тип класса которого является переменной, как это делается в Delphi.
· При описании заголовков метода в хэдере языка C можно не указывать явно идентификаторы параметров – достаточно только типы. Так, в заголовке метода AddSprite указан только тип единственного параметра TSprite* const. Модификатор const играет ту же роль, что и в Delphi – параметр, объявленный как const, - не меняет своего значения внутри функции.
Прокомментируем другой фрагмент кода.
…
// Тип массива следов спрайтов на канве
typedef DynamicArray< DynamicArray < bool > > TTraceMap;
//TTracedSpriteList
class TTracedSpriteList:public TSpriteList
{
…
};
typedef bool __fastcall(__closure *OnMoveEvent)(TSprite* ,TPoint&);
//TSprite
class TSprite:public TObject
{
// Класс TSpriteList, объявленный friend, получает доступ
// к private и protected членам класса TSprite
friend class TSpriteList;
…
protected:
// Методы
void __fastcall virtual PaintPicture()=0;
…
};
Здесь
· Служебное слово typedef указывает на описание типа (подобно type в Delphi).
· Типом динамического массива, названного TTraceMap, является выражение DynamicArray< DynamicArray < bool > >. Оно имеет смысл двумерного массива («массива массивов») переменных логического типа. Имя DynamicArray является именем стандартного шаблона (template), находящегося в библиотеке C++Builder. Это параметризованные, или полиморфные (generic) функции. В Delphi нет аналогов шаблонам. Аргументом шаблона является тип. В данном случае аргументом внутреннего шаблона DynamicArray является тип bool, а аргументом внешнего – сам возвращаемый тип внутреннего шаблона DynamicArray< bool >.
· Класс TTracedSpriteList является наследником класса TSpriteList. В заголовке описания класса TTracedSpriteList присутствует ссылка на наследник TSpriteList с модификатором public. Модификатор public в данном контексте означает, что все члены, наследуемые от TSpriteList, сохраняют свою, заданную предком, доступность и в наследнике (public остается public и т.д.). Если бы модификатором был protected, то все наследуемые члены класса, объявленные в предке с модификаторами public и protected, приобрели бы в наследнике модификатор protected.