První dva háčky co ukáži slouží k přístupu k private a protected částem cizí třídy umístěné v jiné jednotce. Druhý háček je celkem častý a proto s ním začneme.
Protected pole
Pokud má třída definované pole v sekci protected, neměla by jiná třída, která od ní není odvozená mít k těmto polím přístup. Pro usnadnění programování ale Delphi umožňuje třídě, která je definována ve stejné jednotce přistupovat k protected (a private) polím jiné třídy. Této vlastnosti často využívají tvůrci komponent a někdy zapomenou, že by něco mohli i publikovat.
Samozřejmě ideálním řešením je odvodit vlastní třídu, ale někdy to prostě nejde nebo to není výhodné. Řešením je použití háčku.
V jednotce, kde máme touhu dělat nepravosti (tj. přistupovat na cizí pole) definujeme třídu, která je následníkem inkriminované třídy, ale nemá implementaci. Tj. pro případ, kdy chceme přistupovat k protected polí TButton definujeme
1type
2 TOpenButton = class(TButton);
Nyní můžeme náš inkriminované tlačítko prostě přetypovat a jednoduše přistoupit kam potřebujeme. Následuje nic moc příklad:
1TOpenButton(btnTest).SetButtonStyle(true);
Samozřejmě, pokud je místo protected použito strict protected z novějších Delphi tak máte útrum. Což platí i pro strict private.
Private pole
Zatímco předchozí háček je celkem bezpečný a široce používán, druhý se používá až když opravdu jde do tuhého, jelikož je citlivý na změny v základní třídě.
Háček využívá chování kompilátoru. Pro jeho použití musíme znát pořadí polí v sekci private třídy. Pokud tedy nemáme zdrojový kód tak smolík pacholík.
Deklarujeme stínovou třídu, která má i sekci private (proto ten požadavek na zdroják), ale pozor: pořadí jednotlivých polí a jejich typ musí být stejný. Pokud to máme, tak jednoduše už jen cizí třídu přetypujeme na naši stínovou kopii a je to. Tím využijeme dříve popsané chování kdy v rámci jednotky můžeme přistupovat na pole cizí třídy (pokud se tedy nejedná o strict private).
Háček je to pracný a citlivý na změny, proto pozor při jeho používání. Jen pro úplnost připomenu, že pro rozšiřování stávajících tříd lze použít od Delphi 2007 i Class Helper.
Takže malý příklad, kde budou použity oba háčky. Hackujeme TStringList.
1program Project2;
2
3uses
4 SysUtils, Classes;
5
6type
7
8 TShadowStringLists = class(TStrings)
9 private
10 FList: PStringItemList;
11 FCount: Integer;
12 FCapacity: Integer;
13 FSorted: Boolean;
14 FDuplicates: TDuplicates;
15 FOnChange: TNotifyEvent;
16 FOnChanging: TNotifyEvent;
17 end;
18
19
20 TOpenStringList = class(TStringList);
21
22var
23 sl: TStringList;
24begin
25 sl := TStringList.Create;
26 try
27 sl.Add('Prvni');
28 sl.Add('Druhy');
29
30 writeln(TShadowStringLists(sl).FCount);
31
32 writeln(TOpenStringList(sl).Get(0));
33 finally
34 FreeAndNil(sl);
35 end;
36
40end.
Na řádku 8 - 13 je kopie privátních polí TStringList z Classes.pas, TOpenStringList použijeme pro přístup k protected polím (šlo by samozřejmě použít i tu první třídu, ale nechtěl jsem to motat dohromady). Výsledný kód je pak celkem přímočarý (přidáme dva řetezce a přes háčky vypíšeme počet a první položku).
Příště budou další (nečestné a nesportovní) háčky.