Schimbări în Object Pascal

Schimbări în declararea obiectelor. Noul stil de obiecte se declară folosind cuvântul rezervat class, în timp ce vechile obiecte folosesc object. Următoarele sectiuni noi din declaratia obiectelor se aplică la ambele modele de obiecte:

Directiva protected - limitează accesul la sectiunea protejată numai la scopul obiectelor descendente, delimitând astfel interfata publică destinată utilizatorilor de cea protejată destinată dezvoltatorilor de obiecte.

Directiva published - determină generarea de către compilator de informatie accesibilă în timpul rulării (la runtime) despre tipul câmpurilor, proprietătilor si metodelor declarate astfel.

Noul tip de obiecte derivă dintr-un strămos implicit comun - tipul TObject - care permite tratarea lor polimorfică. Declaratia NewObject = class este echivalentă cu NewObject = class(TObject).

Obiectele noi admit acum metode de clasă, care pot fi accesate fără a fi obligatorie utilizarea unei instante de obiect. Următoarele declaratii sunt legale:

NewObject = class(TObject) 
 class function GetClassName: string; 
end; 
... 
AString := NewObject.GetClassName; 

Este posibilă declararea unui tip de obiect pentru a-l face disponibil altor tipuri de obiecte fără a-l defini complet, similar cu declararea de proceduri si functii forward . Spre exemplu :

NewObject = class; 
AnotherObject = class(TObject) 
AField: NewObject; 
... 
end; 
... 
NewObject = class(TObject) 
... 
end; 

Schimbări în utilizarea obiectelor. Obiectele de tip nou nu mai trebuie dereferentiate în mod explicit, întrucât ele sunt alocate dinamic prin constructor si sunt implicit pointeri. Următoarea secventă clasică:

type PNewObject = ^TNewObject; 
TNewObject = object( TObject) 
AField: PNewObject; 
constructor Init; 
end; 
... 
var AnObject: PNewObject; 
begin 
AnObject := new( PNewObject, Init); 
AnObject^.AField := ... 
end; 

este echivalentă acum cu:

type TNewObject = class( TObject); 
AField: TNewObject; 
constructor Create; 
end; 
... 
var AnObject: TNewObject; 
begin 
AnObject := TNewObject.Create; 
AnObject.AField := ... 
end; 

Delphi permite acum declararea de pointeri la metode: tipuri procedurale care sunt metode de obiecte, oferind posibilitatea de a apela o metodă specifică a unei instante specifice de obiect. Următorul cod exemplifică cum dintr-un obiect de tip buton se poate apela o metodă a unui obiect de tip formă :

type TNotifyEvent = procedure( Sender: TObject) of object; 
TXButton = class(TWinControl) 
FOnClick: TNotifyEvent; 
end;
 
TNewForm = class(TXForm) 
procedure ButtonClick( Sender: TObject); 
end; 
... 
var Button: TXButton; 
Form: TNewForm; Ü 
begin 
Button := TXButton.Create; 
Form := TNewForm.Create; 
Button.FOnClick := Form.ButtnClick; 
... 
Button.FOnClick(Button) 
end; 

Delphi introduce conceptul de pointeri la tipuri de obiecte (pointeri la clase), cunoscuti si ca metaclase. Mai jos este o declaratie de pointer la clasă:

type TObjectRef = class of TObject; 

Pointerilor la clasă li se pot atribui ca valoare orice referintă la un tip de obiect mostenit si permit constructii polimorfice de obiecte (prin apelarea de constructori virtuali pentru a crea obiecte al căror tip este cunoscut numai în momentul rulării) precum si utilizarea de metode de clasă pentru tipuri necunoscute la compilare. Pointerul la clasă este un concept cheie în implementarea instantierii de forme cu componente de tip cunoscut numai la runtime.

Un nou operator, is, este utilizat pentru determinarea tipului unui obiect. Expresia AnObject is TObjectType este adevărată dacă AnObject este de tip TObjectType sau descendent din TObjectType. Deasemenea constructia AnObject as TObjectType este echivalentă cu forma clasică TObjectType(AnObject) cu exceptia faptului că operatorul as invocă o exceptie EInvalidCast dacă AnObject nu este de compatibil cu TObjectType.

Proprietăti. Obiectele de tip nou pot avea proprietăti. Din punct de vedere al utilizatorului ele arată ca niste câmpuri dar încapsulează intern (în partea privată sau protejată de obicei) metode care efectuează citirea sau scrierea câmpului. Mecanismul proprietătilor conferă o mare flexibilitate în scrierea codului de manipulare a comportamentului obiectului. Iată mai jos un exemplu pitoresc oferit de Borland:

type THeading = 0..359; 
TCompass = class(TControl) 
private 
FHeading: THeading; 
procedure SetHeading( value: THeading); 
published 
property Heading: THeading read FHeading write SetHeading; 
... 
end; 
... 
procedure TCompass.SetHeading( value: THeading); 
begin 
FHeading := value; 
Update; { redesenează controlul } 
end; 
... 
{ go west: } 
Compass.Heading := 270; 

Proprietătile pot fi vectori si accesibile prin intermediul unui index sau mai multi. Fiecare element al proprietătii este accesat prin intermediul acelorasi metode de citire-scriere. Proprietătile publicate pot fi stocate în resurse si pot avea valori implicite. Această facilitate este utilizată de editorul vizual pentru citirea si salvarea componentelor particularizate dintr-o formă.

Proprietătile pot fi făcute vizibile sau ascunse utilizatorului de obiecte prin redeclararea lor în sectiunile public, published sau protected a tipurilor descendente de obiecte. Deasemenea o proprietate fără metodă sau câmp de citire este o proprietate write-only iar una fără metodă de scriere devine read-only.

Modificări în dispecerizarea metodelor. Ca urmare a numărului mare de metode virtuale pe care au ajuns să le posede obiectele curente, Borland a recurs la o schemă hibridă de dispecerizare a metodelor. Au reapărut metodele dinamice declarate cu declarate cu dynamic care necesită mai putină memorie, în timp ce metodele virtuale sunt mai rapide. Ca urmare a folosirii ambelor tehnici, se utilizează acum directiva override la reutilizarea unei metode în loc de repeta virtual sau dynamic, care ar echivala cu redefinirea unei noi metode.

Metodele de răspuns la mesaje sunt tot metode dinamice cu interfată mai sugestivă decât parametrul clasic de tip TMessage, acum utilizând parametri de tipuri specifice fiecărui mesaj precum TWMPaint, TWMChar, TWMClose, etc. A devenit mai simplă invocarea răspunsului implicit la mesaj al obiectului mostenit: se foloseste doar inherited; .

Obiectele de tip nou admit acum constructori virtuali.

Utilizarea de vectori deschisi ca parametri de functie sau procedură. Vectorii deschisi ca parametri permit transmiterea de vectori de orice dimensiune unei proceduri sau functii. Declararea unui parametru formal ca vector deschis urmează sintaxa T, unde T este un identificator de tip. Parametrul actual trebuie să fie o variabilă de tip T sau un vector cu elemente de tip T. În interiorul procedurii vectorul parametru formal se comportă ca si cum ar fi declarat cu array[0..N-1] of T, unde N este numărul de elemente al vectorului parametru actual.

Vectorul deschis ca parametru formal nu poate fi transmis mai departe altor functii sau proceduri decât tot astfel sau ca paramteru fără tip transmis prin referintă.

Dimensiunea unui vector deschis parametru formal se determină cu SizeOf, în timp ce indexul primului element este 0 iar indexul ultimului element se determină cu functia High. Ü

Există posibilitatea utilizării de vectori deschisi declarati ca array of const; prin care un vector cu elemente de tipuri diferite poate fi transmis unei proceduri sau functii.

Apelul tipic de proceduri sau functii cu parametru actual vector deschis se face fără declarări de variabilă sau asignari de valori elementelor:

SomeProc([21, 6, 64]) sau SomeProc([x, y, 10, 10]) . 

Variabila Result în functii. Fiecare functie detine o variabilă locală implicită Result de acelasi tip ca functia, responsabilă pentru păstrarea valorii returnate de functie, si care poate fi utilizată în atribuiri atât în partea stângă, cât si în partea dreaptă a unei expresii fără a genera apeluri recursive ale functiei. Desigur, vechiul stil de utilizare a numelui functiei rămâne valabil.

Tipurile rezultatelor returnate de functii. Functiile pot returna rezultate de orice tip, simplu sau complex, standard sau definit de utilizator, exceptând obiecte de stil vechi (pentru care se utilizează pointeri la obiecte, ca si până acum) si fisiere de tip text sau file of.

Optimizarea constructiilor case. Domeniile de valori dintr-o constructie case nu trebuie să se suprapună, în timp ce utilizarea constantelor în ordine ascendentă permite compilatorului optimizarea case-ului prin instructiuni de salt.

Tratarea exceptiilor. Când survine o conditie de eroare, aplicatia invocă o exceptie, respectiv crează un obiect exceptie. Fluxul normal de executie a codului este întrerupt si controlul executiei revine unui bloc de "făcut curătenie după exceptie", unui bloc de tratare a exceptiei, sau ambelor, după care se execută codul normal care urmează după blocul de cod care a tratat exceptia.

Blocurile de protectie a codului la exceptii pot fi imbricate, garantând astfel că aparitia unei exceptii nu duce la rejectarea întregului cod.

Mai jos este prezentat modelul imbricat de protejare a alocării resurselor:

{ începe blocul protejat } 
try 
{alocă prima resursă} 
try 
{alocă cea de-a doua resursă} 
try 
{cod care foloseste ambele resurse} 
finally 
{cod de curătenie care este executat întotdeauna 
indiferent de exceptie si eliberează a doua 
resursă} 
end; 
finally 
{cod de curâtenie care eliberează prima resursă} 
end; 
except 
{cod de tratare globală a exceptiei - se execută 
numai în caz de exceptie} 
end; 
De obicei, exceptii diferite se tratează pe nivele diferite: 
try 
{ cod protejat } 
try 
{ cod special protejat } 
except 
{tratează exceptiile specifice} 
end; 
except 
{ tratează exceptiile globale } 
end; 

Exceptiile permit eliminarea din cod a verificărilor si tratărilor conditiilor de eroare, simplificând dramatic codul principal si elimnând astfel surse suplimentare de erori. Spre exemplu următoarea secventă clasică de cod:

if Number <> 0 then Result := Sum div Number 
else Result := 0 
poate fi înlocuită cu 
try 
Result := Sum div Number; 
except 
on EDivByZero do Result := 0 
end; 

Pentru a indica o eroare în program se poate invoca o exceptie prin utilizarea cuvântului rezervat raise urmat de o instantă a unui obiect exceptie:

type EPasswordInvalid = class(Exception); 
... 
if Password <> AcceptedPassword then 
raise EPasswordInvalid( 'Acces refuzat: Parolă incorectă!'); 

În exemplul de mai sus codul care urmează este "sărit" si controlul executiei revine după blocul de cod care tratează exceptia EPasswordInvalid sau care tratează implicit toate exceptiile.


(C) Copyright Computer Press Agora