Veskrze každý zná základní třídu TObject a její metody jako Free, constructor Create a destructor Destroy. Asi znáte i užitečnou class function ClassName, která vrací název třídy a sem tam šikovné metody ClassType a ClassParent, které vrací TClass, tj. referenci na třídu za běhu.
Rád bych upozornil na některé zajímavé elementy deklarace TObject. Níže je deklarace třídy tak, jak je v Delphi 2010.
Modří již vědí, že v Delphi 2009 došlo k rozšíření o čtyři kousky a to o class function UnitName a tři virtuální metody - Equals, GetHashCode a ToString - velmi užitečné a navíc prudce zvyšující kompatibilitu s Delphi Prism a .NET.
Delphi 2010 jen navíc určuje viditelnost na public (asi vzhledem k novému RTTI) a ClassInfo je inline.
Deklarace TObject
1TObject = class
2 public
3 constructor Create;
4 procedure Free;
5 class function InitInstance(Instance: Pointer): TObject;
6 procedure CleanupInstance;
7 function ClassType: TClass; inline;
8 class function ClassName: string;
9 class function ClassNameIs(const Name: string): Boolean;
10 class function ClassParent: TClass;
11 class function ClassInfo: Pointer; inline;
12 class function InstanceSize: Longint; inline;
13 class function InheritsFrom(AClass: TClass): Boolean;
14 class function MethodAddress(const Name: ShortString): Pointer; overload;
15 class function MethodAddress(const Name: string): Pointer; overload;
16 class function MethodName(Address: Pointer): string;
17 function FieldAddress(const Name: ShortString): Pointer; overload;
18 function FieldAddress(const Name: string): Pointer; overload;
19 function GetInterface(const IID: TGUID; out Obj): Boolean;
20 class function GetInterfaceEntry(const IID: TGUID): PInterfaceEntry;
21 class function GetInterfaceTable: PInterfaceTable;
22 class function UnitName: string;
23 function Equals(Obj: TObject): Boolean; virtual;
24 function GetHashCode: Integer; virtual;
25 function ToString: string; virtual;
26 function SafeCallException(ExceptObject: TObject;
27 ExceptAddr: Pointer): HResult; virtual;
28 procedure AfterConstruction; virtual;
29 procedure BeforeDestruction; virtual;
30 procedure Dispatch(var Message); virtual;
31 procedure DefaultHandler(var Message); virtual;
32 class function NewInstance: TObject; virtual;
33 procedure FreeInstance; virtual;
34 destructor Destroy; virtual;
35 end;
Jak jsem řekl, ClassType je málo využívaná, většinou si člověk vystačí s is a as, ale např. můžete mít za běhu seznam tříd (ne objektů) a v kombinaci s ClassName vybrat požadovanou třídu a její referenci získanou právě přes ClassType předat dále ke zpracování atd.
ClassParent jsem použil např. tak, že jsem měl definován seznam názvů tříd formulářů a k nim definovanou externě ikonu. A při požadavku na vznik některého následníka, jsem našel poslední definovanou ikonu v hierarchii požadované třídy. Ale určitě Vás napadne i jiné použití.
ClassInfo vrací ukazatal na RTTI. Pro pěknou práci s RTTI slouží jednotka typinfo a už tu RTTI bylo.
InstanceSize vrací překvapivě velikost instance. writeln(TObject.InstanceSize); vrátí 8 byte.
TObject.AfterConstruction a TObject.BeforeDestruction
AfterConstruction a BeforeDestruction jsou volány v patřičných okamžicích, ve VCL jsou používány např. na vytvoření TForm.OnCreate. Podle helpu BeforeDestruction není volán, pokud došlo v konstruktoru k výjimce.
1type
2 TDemoObject = class (TObject)
3 public
4 constructor Create;
5 destructor Destroy; override;
6 procedure AfterConstruction; override;
7 procedure BeforeDestruction; override;
8 end;
9
10
11
12procedure TDemoObject.AfterConstruction;
13begin
14 writeln('AfterConstruction');
15end;
16
17procedure TDemoObject.BeforeDestruction;
18begin
19 writeln('BeforeDestruction');
20end;
21
22constructor TDemoObject.Create;
23begin
24 writeln('Create');
25end;
26
27destructor TDemoObject.Destroy;
28begin
29 writeln('Destroy');
30 inherited;
31end;
32
33begin
34 with TDemoObject.Create do
35 Free;
36end.
Výsledek běhu:
Create
AfterConstruction
BeforeDestruction
Destroy
TObject.UnitName
UnitName by neměl ničím překvapit.
1program Muj.Cool.Project.SP2;
2
3uses
4 SysUtils;
5type
6 TDemoObject = class (TObject);
7begin
8 writeln(TDemoObject.UnitName);
9end.
Vypíše: Muj.Cool.Project.SP2, čímž se nenápadně dostáváme k tomu, že názvy jednotek mohou být strukturované.
TObject.Equals
Nová metoda, která vrací zda jsou instance stejné. V základu toho moc neumí, ale jelikož je virtuální tak se otevírají zajímavé možnosti.
1function TObject.Equals(Obj: TObject): Boolean;
2begin
3 Result := Obj = Self;
4end;
TObject.ToString
Základní implementace volá ClassName tj. název třídy.
1function TObject.ToString: string;
2begin
3 Result := ClassName;
4end;
Mezi třídy, které ji předefinovávají patří třeba TStringWriter nebo Exception.
TObject.GetHashCode
Opět nová virtuální metodu, která vrací integer s hashcode. Základní implementace:
1function TObject.GetHashCode: Integer;
2begin
3 Result := Integer(Self);
4end;
Osobně nechápu proč není nějaká jednoduchá funkce na získání hashe stringu ( - už jsem ji našel, viz dále), takže použijte následující kód.
1program TestHash;
2
3
4uses
5 Generics.Defaults;
6
7function GetHashCode(const s:AnsiString):Integer;
8begin
9 Result := BobJenkinsHash(s[1], Length(s) * SizeOf(s[1]), 0);
10end;
11
12begin
13 writeln(GetHashCode('delphi.cz'));
14end.
No a nebo použijte SysUtils.HashName - writeln(HashName('delphi.cz'));