Documente online.
Zona de administrare documente. Fisierele tale
Am uitat parola x Creaza cont nou
 HomeExploreaza
upload
Upload




Concepte avansate in programarea Object Pascal - delphi

Informatica


Concepte avansate în programarea Object Pascal

În aceasta sectiune ne propunem sa luam în discutie o serie de aspecte care subliniaza pregnant noutatea ofertei Delphi, în principal, în materie de programare obiect orientata. Se va putea observa la finalul sectiunii, efortul facut de cei care au specificat Object Pascal, pentru a apropia acest limbaj de standardele de facto în programarea obiect orientata si, totodata, de a pastra proprietatile limbajului Pascal specificate de primul lui parinte Niklaus Wirth.



3.1 Clase în Object Pascal

Programatorii Pascal îsi amintesc de faptul ca, ceea ce în modelarea obiect orientata se numeste clasa, în Pascal are ca echivalent tipul obiect. Ca forma de comunicare a ideilor referitoare la solutia obiect orientata a unei probleme, tipul obiect poate fi utilizat ca substitut pentru clasa. Din punct de vedere al sintaxei de definire a unei clase, vom vedea ca, în Object Pascal s-a adoptat cuvântul cheie class în locul cuvântului cheie object, pentru a defini o clasa. Coceptul de clasa în programarea Object Pascal introduce si o serie de alte elemente care fac din programarea pe obiecte un instrument deosebit de puternic, în realizarea de aplicatii fiabile, extensibile, puternic interactive, inclusiv în faza de proiectare asistata de mediul Delphi. Extensia cheie a limbajului Object Pascal pentru marirea interactivitatii aplicatiilor Delphi se refera la introducerea conceptului de proprietate.

O data de tip class este o structura care se compune dintr-un numar fix de componente(membri). Componentele posibile ale unei clase sunt: câmpurile, metodele si proprietatile. Spre deosebire de alte tipuri, un tip class poate fi declarat doar în sectiunea de declarare a tipurilor cea mai exterioara a programului sau unit-ului. Astfel ca, un tip class nu poate fi declarat în sectiunea de declarare a variabilelor sau în interiorul procedurilor, functiilor sau în blocul de definitie al metodelor.

Sintaxa de declarare a tipului class este:

<TClasa_Utilizator>=class [(<TClasa_Definitoare>)]

public

  <Nume_Camp>:<Tip_Camp>;

.

<Antet_Metoda>

.

property

<Nume_Proprietate>:<Tip_Proprietate>

read <Nume_Camp/Nume metoda>

write < Nume_Camp/Nume metoda>

  private

:

protected

 

published

 

end;

Domenii de vizibilitate

Componentele unei clase pot avea domenii de vizibilitate diferite, în functie de directiva de specificare a vizibilitatii sub a carei incidenta se afla. Dupa cum se vede si mai sus, aceste directive de specificare a vizibilitatii sunt: private, protected, public si published. Aceste directive restrictioneaza vizibilitatea componentelor în situatia în care alte unit-uri forteaza accesul la ele. În interiorul unit-ului în care este definita clasa, toate componentele sunt vizibile.

Observatie

Spre deosebire de multi alti identificatori utilizati în declararea tipurilor, directivele de specificare a vizibilitatii nu sunt cuvinte rezervate în afara contextului care ocazioneaza declararea clasei. În practica se recomanda, totusi, sa le tratam ca si când ar fi cuvinte rezervate, în adevaratul sens al cuvântului.

Directivele de specificare a vizibilitatii nu trebuie mentionate explicit pentru fiecare membru al clasei. Regula este ca dupa o directiva de specificare a vizibilitatii sa urmeze toti membrii care au acelasi tip de vizibilitate. Un domeniu de vizibilitate se termina în momentul în care este întâlnita alta directiva de specificare a vizibilitatii.

Specificatorul de vizibilitate private

Acest specificator este cel mai restrictiv. Membrii privati ai unei clase nu se vad în afara unit-ului în care este definita clasa. De obicei se declara ca private componente ale caror valori sunt critice pentru comportamentul instantelor clasei respective. Daca avem nevoie de doua clase care trebuie sa aiba acces reciproc la componentele lor, atunci aceste clase se vor defini în acelasi unit. Detaliile de implementare sunt complet ascunse fata de end-user.

Specificatorul de vizibilitate protected

Specificatorul de vizibilitate protected relaxeaza restrictiile de vizibilitate, în sensul ca, componente declarate ca protected într-o clasa pot fi accesate de obiecte care fac parte din domeniul clasei; altfel spus, descendentii unei clasei au acces la componentele din sectiunea protected a acesteia. Detaliile de implementare ramân în continuare ascunse fata de end-user.

Specificatorul de vizibilitate public

Componentele publice sunt vizibile oriunde este vizibila si clasa. Nu se aplica alte restrictii asupra componentelor publice ale unei clase.

Specificatorul de vizibilitate published

Declararea unei componente ca fiind de tip published, informeaza compilatorul ca trebuie sa genereze informatii de tip run-time (RunTime Type Information-RTTI) pentru componenta respectiva.

Informatiile de tip run-time permit unei aplicatii externe sa afle date despre câmpurile, metodele sau proprietatile unui obiect, despre clasa definitoare a obiectului, etc.

Pe timpul executiei unui program, din punct de vedere al vizibilitatii, o componenta published se comporta ca si când ar fi o componenta de tip public. Toate componentele published sunt vizibile în orice unit unde clasa care le încapsuleaza este vizibila. Diferenta consta în faptul ca, o aplicatie externa poate obtine informatii de tip run-time despre componentele published.

Ca un exemplu, inspectorul de obiecte al sistemului Delphi foloseste interfetele published ale obiectelor din Paleta de Componente a sistemului Delphi pentru a determina ce proprietati si evenimente trebuie vizualizate în timpul proiectarii unei aplicatii.

Exista anumite restrictii în ceea ce priveste modul de utilizarea al directivei published.

O clasa poate avea componente published daca este compilata sub incidenta directivei având starea sau daca este derivata dintr-o clasa care deja a fost compilata astfel încât sa aiba componente published. Directiva controleaza generarea RTTI.

Un câmp definit într-o sectiune published trebuie sa fie de tip clasa. Câmpurile de orice alt tip trebuie plasate în sectiunile public, protected sau private.

Proprietatile published sunt restrictionate din punct de vedere al tipului. Sunt acceptate proprietati de tip:

-ordinal;

-real(Single, Double, Extended, Comp, nu si real);

-sir de caractere;

-multime (small set);

-clasa;

-identificator de metoda (dar nu tip procedural global)

Small set desemneaza un tip multime al carui tip de baza este ordinal si ale carui valori ordinale sunt cuprinse între 0 si 50.

Metode

În procesul de definire a unei clase, metodele leaga codul cu tipurile de date pe care codul este abilitat sa le manipuleze. În acest scop, metodele au dreptul sa acceseze câmpurile unui obiect fara ca acestea sa-i fie trimise explicit ca parametri.

Declararea unei metode are doua parti: declararea signaturii metodei în procesul de definire a clasei si implementarea corpului metodei în afara definitiei clasei, dar în acelasi unit în care s-a definit si clasa. De la programarea Pascal OO se stie ca declararea signaturii este asemanatoare unei declaratii forward de procedura sau functie. De subliniat ceea ce, de asemenea, se stie de la Pascal OO si anume faptul ca implementarea corpului metodei presupune ca antetul ei sa specifice numele clasei din a carei definitie face parte metoda. Referitor la implementarea unei metode mai facem urmatoarele precizari:

În interiorul corpului unei metode, o instructiune care apeleaza o functie sau o procedura permite utilizarea designatorilor de metoda calificata pentru a activa o anumita metoda a unei clase. Un designator de metoda poate fi o variabila referinta la un obiect sau o referinta la o clasa. Cuvântul rezervat inherited desemneaza stramosul tipului obiect care include metoda. Prezentam în continuare un exemplu de definire a unei clase împreuna cu implementarea metodei aferente în care se utilizeaza si cuvântul rezervat inherited.

type

TFramedLabel = class(TLabel)

  protected

  procedure Paint; override;

  end;

procedure TFramedLabel.Paint;

begin

inherited Paint;

with Canvas do

begin

  Brush.Color := clWindowText;

  Brush.Style := bsSolid;

  FrameRect(ClientRect);

end;

end

În interiorul blocului care corespunde implementarii unei metode, regulile de vizibilitate sunt, dupa cum poate ca s-a înteles, diferite de regulile de vizibilitate pentru proceduri si functii oarecare. Accesul la componentele unui obiect din interiorul unei metode este simplificat datorita inserarii automate în codul unei metode a unei calificari de tipul:

with Self do

begin

...

end

Variabila Self este o variabila de acelasi tip cu clasa în care apare metoda.

Implicit metodele sunt statice.

Object Pascal propune însa si alte tipuri de metode, din perspectiva modului de rezolvare a apelului acestora. Le prezentam în Tabelul 3.1.

Directiva
Efect

Virtual

Metoda apelata este determinata cu ajutorul tabelei VMT

Dynamic

Metoda apelata este determinata cu ajutorul tabelei de metode dinamice

Message

Metoda apelata este determinata cu ajutorul mecanismului de transmitere a mesajelor

Abstract

Metoda nu are implementare dar trebuie redefinita în aval

Override

Metoda redefineste o metoda virtuala sai dinamica

Class

Apel de metoda fara a utiliza variabila implicita Self

Tabelul 3.1 Tipuri de metode în Object Pascal

Evident, în Object Pascal pot fi metode :procedurile, functiile, constructorii si destructorii. În linii mari, constructorii si destructorii se utilizeaza cu semnificatia care se cunoaste de la limbajul Pascal.

Metode statice

Metodele declarate într-o clasa sunt implicit statice. Nu este necesar un identificator special pentru a desemna o metoda de tip static. Când este apelata o metoda statica, tipul variabile este cel care determina ce metoda urmeaza sa fie executata. Compilatorul determina exact adresa metodei în timpul compilarii.

Avantajul fundamental al metodelor statice consta în faptul ca executarea lor este foarte rapida. Prin contrast, metodele virtuale si dinamice rezolva în timpul executiei problema legarii codului care trebuie executat, ceea ce lungeste timpul de executie al programelor daca se abuzeaza de apelul la metode virtuale sau dinamice.

O metoda statica nu poate fi schimbata când este mostenita de un descendent al clasei în care aceasta este definita. Altfel spus, daca declarati o clasa care include în definitie o metoda statica, atunci derivând o noua clasa din aceasta, clasa derivata partajeaza exact aceeasi metoda, situata la aceeasi adresa. Aceasta înseamna ca nu putem redefini static metodele.

În exemplul de mai jos, prima clasa declara doua metode statice. Cea de-a doua clasa declara doua metode statice cu acelasi nume, care înlocuiesc metodele mostenite de la prima clasa.

type

TFirstComponent = class(TComponent)

  procedure Move;

  procedure Flash;

  end;

TSecondComponent = class(TFirstComponent)

  procedure Move;

  function Flash(HowOften: Integer): Integer;

  end;

Metode virtuale

Spre deosebire de apelul metodele statice, apelurile metodelor virtuale nu sunt rezolvate în faza de compilare. Metoda care urmeaza sa fie executata, în cazul virtual este determinata în timpul executiei printr-un procedeu numit legare întârziata. Orice metoda poate fi facuta virtuala prin mentionarea unei directive virtual la sfârsitul definitiei metodei în lista de componente a clasei. Noutatea metodelor virtuale consta în urmatorul mecanism: daca într-un lant de derivare, o anumita metoda, declarata virtuala în clasa radacina, apare în descendenti redefinita (marcata de directiva override), atunci un apel la metoda respectiva, facut din contextul unei variabile compatibila cu lantul de derivare, va fi rezolvat în functie de tipul curent al variabilei. Tipul variabilei este stabilit în momentul crearii instantei, de catre constructorul corespunzator clasei context.

Alegerea metodei corespunzatoare contextului se face cu ajutorul tabelelor VMT, unice, asociate claselor care au metode virtuale si create la apelarea constructorilor.

Metode dinamice

Un mecanism oarecum similar metodelor virtuale este utilizat si în cazul metodelor dinamice. Din punctul de vedere al utilizatorului nu se poate face diferenta între cele doua tipuri de metode. Codul generat, însa, difera semnificativ, astfel: apelurile metodelor virtuale sunt mai rapide dar genereaza cresterea codului; apelurile metodelor dinamice sunt mai lente, dar genereaza cod mai mare.

În mod uzual, metodele virtuale sunt preferate daca se doreste exploatarea capabilitatilor polimorfice ale unui lant de derivare. Daca, însa, se doreste crearea unei clase de baza din care se deriveaza un numar mare de descendenti, si în fiecare descendent se redefineste un numar mic de metode virtuale mostenite.

Metode de tip mesaj

Aceste metode sunt o forma specializata a metodelor dinamice, fiind indispensabile în manipularea eficienta a mesajelor unei aplicatii Delphi. Compilatorul Object Pascal genereaza cod de apel specific acestor metode daca sunt declarate cu directiva message. Mecaismul de apel utilizat este aproape identic cu cel utilizat în cazul metodelo dinamice. Exista, însa, si elemente specifice de care programatorul trebuie sa tina cont când utilizeaza aceste tipuri de metode. Aceste elemente specifice sunt legate de protocolul de gestiune a mesajelor unei aplicatii într-o aplicatie Windows, în genere si într-o aplicatie Delphi, în particular.

Prezentam, în continuare, un exemplu de specificare a unui handler utilizator de mesaje.

const

CM_CHANGECOLOR = WM_USER + 400;

type

TMyComponent = class(TControl)

  ...



  protected

  procedure CMChangeColor(var Message: TMessage): message

  CM_CHANGECOLOR;

.

  end;

procedure TMyComponent.CMChangeColor(var Message: TMessage);

begin

Color := Message.lParam;

inherited;

end

Recomand studierea atenta a help-ului on-line Delphi si a exemplelor demonstrative, pentru a aprofunda problematica lucrului cu mesajele în aplicatiile Delphi.

Metode abstracte

De regula când se specifica o metoda în lista de componente asociata definitiei unei clase, compilatorul se asteapta sa gaseasca implementarea metodei în sectiunea corespunzatoare a unit-ului gazda. Pe de alta parte, atunci când se specifica o metoda în clasa de baza, se stabileste un comportament implicit al tuturor descendentilor, relativ la metoda respectiva. Pentru a schimba comportamentul în descendenti, trebuie redefinita metoda în descendenti. Daca nu are sens asocierea în clasa de baza a unui comportament implicit, se poate utiliza directiva abstract, pentru a semnala compilatorului ca nu va fi implementata o metoda implicita. De precizat faptul ca orice metoda declarata abstracta trebuie sa fi, totodata virtuala sau dinamica, ca în exemplul de mai jos.

type

Base = class

procedure DaliVision; virtual; abstract;

procedure TellyVision; dynamic; abstract;

end;

Metode redefinite (override)

Atunci când logica unui lant de derivare impune redefinirea unor metode ( virtuale sau dinamice), în descendenti se anunta redefinirea cu ajutorul directivei override. Pentru a ilustra ideea, prezentam si exemplul de mai jos.

type

TFirstComponent = class(TCustomControl)

  procedure Move;

  procedure Flash; virtual;

  procedure Beep; dynamic;

  end;

TSecondComponent = class(TFirstComponent)

  procedure Move;

  procedure Flash; override;

  procedure Beep; override;

  end;

Metode de tip clasa

Metodele de tip clasa nu sunt altceva decât metode ce pot fi apelate ca orice alte proceduri sau functii obisnuite, fara a fi nevoie de vreo instantiere a clasei care le-a definit. Acest tip de metode sunt usor de recunoscut prin prefixarea lor cu directiva class ca în exemplul de mai jos.

Trebuie retinut însa ca metodele de tip clasa nu trebuie sa modifice informatii relative la instante. Astfel ca, în exemplul:

type

Tclass1 = class

Nume:string;

class procedure ModificNume (NumeNou:string);

end;

class procedure ModificNume (NumeNou:string);

begin

Nume:=NumeNou;

end

compilatorul va semnala eroare deoarece metoda de tip clasa ModificNume încearca sa modifice valoarea câmpului Nume, care este o variabila de instanta a clasei Tclass1. Unit-ul System defineste doua tipuri, TObject si TClass, care sunt tipuri radacina pentru toate tipurile clasa si referinta la clasa,despre care vom discuta în continuare. Radacina TObject contine o bogata colectie de metode de tip clasa pe care le putem apela fara a fi nevoie sa instantiem clasa.

type

TObject = class;

TClass = class of TObject;

TObject = class

constructor Create;

destructor Destroy; virtual;

class function ClassInfo: Pointer;

class function ClassName: ShortString;

class function ClassNameIs(const Name: string): Boolean;

class function ClassParent: TClass;

function ClassType: TClass;

procedure CleanupInstance;

procedure DefaultHandler(var Message); virtual;

procedure Dispatch(var Message);

function FieldAddress(const Name: ShortString): Pointer;

procedure Free;

procedure FreeInstance; virtual;

class function InheritsFrom(AClass: TClass): Boolean;

class function InitInstance(Instance: Pointer): TObject;

class function InstanceSize: Longint;

class function NewInstance: TObject; virtual;

class function MethodAddress(const Name: ShortString): Pointer;

class function MethodName(Address: Pointer): ShortString;

end;

Conceptul de proprietate

Conceptul de proprietate nu este absolut nou. În Turbo Pascal, proprietatile se confundau cu înregistrarile sau câmpurile unui obiect. În Delphi, notiunea de proprietate, ca si concept nou, pare sa fie strâns legata de necesitatile programarii vizuale. Este adevarat doar în parte deoarece notiunea de proprietate are o valoare de întrebuintare care depaseste cerintele programarii vizuale. O definitie de proprietate într-o clasa permite declararea unui anumit atribut al obiectelor unei clase si a actiunilor asociate cu citirea si scrierea atributelor. Exemple de astfel de proprietati sunt : proprietatea "Caption" a unei forme, marimea fontului intr-un derivat TMemo, etc.

Putem spune ca proprietatile sunt o extensie naturala a câmpurilor unui obiect. Atât câmpurile cât si proprietatile pot fi utilizate pentru a exprima atributele unui obiect, dar, în timp ce câmpurile sunt doar locatii de memorie care pot fi examinate si modificate dupa dorinta, proprietatile asigura un control mai mare asupra valorilor atributelor, datorita mecanismelor de citire /scriere cu care se asociaza o anumita proprietate.

Prezentam mai jos, cu ajutorul limbajului diagramelor de sintaxa, regulile sintactice care stau la baza specificarii proprietatilor unei clase.

Definitie proprietate


Definitie interfata proprietate


Definitie lista parametri proprietate


Definitie specificatori proprietate


Definitie specificator read


Definitie specificator write


Definitie specificator de stocare


Definitie specificator implicit


Definitie Câmp / Metoda


Modul de utilizare al sintaxei de mai sus poate fi urmarit si din exemplul prezentat în continuare, care ne arata modul de scriere a codului sursa al unei componente în Delphi.

unit Exemplu;

interface

uses

Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;

type

TArrayProp = array [1..5] of string[7];

TEverything = class(TCustomControl)

private

FArrayProp : TArrayProp;

function GetArrayPropInt(pIndex: integer): string;

function GetArrayPropStr(pIndex: string): integer;

protected

public

constructor Create(AOwner: TComponent); override;

property ArrayPropInt[Index: integer]: string read GetArrayPropInt;

property ArrayPropStr[Index: string]: integer read GetArrayPropStr;

published

end;

procedure Register;

implementation

constructor TEverything.Create(AOwner: TComponent);

begin

// Initializare FArrayProp

FArrayProp[1] := 'one';

FArrayProp[2] := 'two';

FArrayProp[3] := 'three';

FArrayProp[4] := 'four';

FArrayProp[5] := 'five';

end



function TEverything.GetArrayPropInt(pIndex: integer): string;

begin

result := 'Necunoscut';

// Daca pIndex este definit în FArrayProp, seteaza variabila result la valoarea de //indice pIndex

if pIndex in [1..5] then

result := FArrayProp[pIndex];

end

function TEverything.GetArrayPropStr(pIndex: string): integer;

var

x : integer;

begin

result := -1;

for x := 1 to 5 do

if UpperCase(FArrayProp[x]) = UpperCase(pIndex) then

begin

result := x;

exit;

end;

end

procedure Register;

begin

RegisterComponents('UD3', [TEverything]);

end

end

3.2 Tratarea exceptiilor în Delphi

Printre caracteristicile principale ale mediului Delphi, una dintre cele mai importante este capacitatea de tratare a exceptiilor, prin care programatorul poate sa raspunda elegant la aparitia oricarei erori de executie, simplificând astfel si codul, ceea ce permite programatorului sa se concentreze asupra algoritmilor principali ai aplicatiei. Exceptiile în Delphi sunt similare celor folosite de C++, locul lui catch este preluat de except iar throw devine raise în Delphi. La fel ca în C++ exceptiile sunt manipulate în blocuri, care la rândul lor pot sa suporte incluziunea.

Blocuri de protectie

În Delphi, tratarea exceptiilor se face prin asa numitele blocuri de protectie, care pot executa, fie un cod de terminare pentru a nu fi compromisa sesiunea Windows, fie o secventa de cod care trateaza efectiv exceptia, caz în care executia programului continua normal.

Aceste blocuri de protectie sunt la rândul lor compuse din alte doua tipuri de blocuri, un bloc de garda, care, asa dupa cum îi spune numele este raspunzator de interceptarea exceptiei si un bloc de raspuns ce contine codul de tratare al exceptiei, sau codul corespunzator terminarii aplicatiei.

Structura de principiu a unui bloc de protectie în Delphi este:

try

finally

end;

sau

try

except

end;

În varianta cu finally executia decurge astfel:

Daca vreuna dintre instructiunile cuprinse între try si finally provoaca o exceptie, atunci sistemul preda controlul blocului de raspuns, cuprins între finally si end. Daca nu a aparut nici o exceptie, dupa epuizarea instructiunilor cuprinse între try si finally, se continua cu executia instructiunilor cuprinse între finally si end.

Altfel spus, în varianta cu finally avem la dispozitie un mecanism cu ajutorul caruia avem garantia ca se executa un cod de terminare corecta a unui tip de prelucrare, indiferent de exceptiile care pot apare. Prin acest mecanism se urmareste limitarea efectelor posibilelor exceptii la executia unui program Delphi.

Sa mai adaugam faptul ca, în varianta cu finally, dupa executia codului de terminare, daca a aparut o exceptie, aceasta îsi continua evolutia (nu este ridicata), putând fi interceptata si tratata într-o bucla try externa, iar daca aceasta bucla nu este gasita, putând provoca în cele din urma terminarea anormala a programului.

În varianta cu except executia decurge astfel:

Lista instructiunilor din blocul try se executa în ordine. Daca nu apare nici o eroare, blocul except este ignorat, continuându-se executia cu prima instructiune aflata dupa end. Daca a aparut o exceptie, controlul este dat celui mai interior handler de exceptie existent. Daca un astfel de handler de exceptie nu exista, atunci se va cauta un handler de exceptii în exterior, în alt bloc try-except, neterminat înca. Daca un astfel de handler nu este gasit, se continua astfel pâna la epuizarea blocurilor try-except, sau pâna la gasirea handler-ului de exceptie adecvat. Daca nu este gasit nici un handler, se genereaza un mesaj standard de eroare si executia este terminata anormal.

În sfârsit, sa mai adaugam precizarea ca, similar modului în care utilizam în C++ enuntul throw, în Object Pascal putem folosi enuntul raise pentru a genera o exceptie.

Delphi pune la dispozitia programatorului clase de exceptii, extrem de utile pentru a monitoriza sistematic aparitia exceptiilor uzuale ale unei aplicatii Delphi (împartie la zero, acces nepermis la memorie, eroare la crearea unui fosier, etc.).

Amanunte despre protocolul de utilizare si detaliile de sintaxa pot fi urmarite si în exemplele de mai jos.

unit UExcept1;

interface

uses

Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,

StdCtrls;

type

TForm1 = class(TForm)

Edit1: TEdit;

Label1: TLabel;

Edit2: TEdit;

Label2: TLabel;

Button1: TButton;

Label3: TLabel;

Edit3: TEdit;

procedure Button1Click(Sender: TObject);

private

public

end;

var

Form1: TForm1;

Op1,Op2,Rezultat:real;

implementation

procedure TForm1.Button1Click(Sender: TObject);

begin

try

try

Op1:=StrToFloat(Edit1.Text);

Op2:=StrToFloat(Edit2.Text);

Rezultat:=Op1/Op2;

except

on EConvertError do

ShowMessage('Operanzi eronati...');

end;

Edit3.Text:=FloatToStr(Rezultat);

Edit1.SetFocus;

Edit1.Text:='';

Edit2.Text:='';

except

on EZeroDivide do

ShowMessage('Impartire la zero...');

end;

end

end

unit UEcept2;

//Aplicatie la tratarea exceptiilor in Delphi

interface

uses

Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,

StdCtrls, Buttons;

// Codul care urmeaza este o interfata intre

//exceptiile aplicatiilor utilizator si sistem

// asigurata de clasa Exception din unit-ul SYSUTILS, prezentata mai jos sub forma de //comentariu.

(*Exception = class(TObject)

private

FMessage: string;

FHelpContext: Integer;

public

constructor Create(const Msg: string);

constructor CreateFmt(const Msg: string; const Args: array of const);

constructor CreateRes(Ident: integer);

constructor CreateResFmt(Ident: integer; const Args: array of const);

constructor CreateHelp(const Msg: string; AHelpContext: integer);

constructor CreateFmtHelp(const Msg: string; const Args: array of const;

AHelpContext: integer);

constructor CreateResHelp(Ident: integer; AHelpContext: integer);

constructor CreateResFmtHelp(Ident: integer; const Args: array of const;

AHelpContext: integer);

property HelpContext: integer read FHelpContext write FHelpContext;

property Message: string read FMessage write FMessage;

end;

type

EMyComponentError = class(Exception)

  private

  FErrorCode: integer;

  public

  property ErrorCode: integer read FErrorCode write FErrorCode;

  constructor Create(const Msg: string; ErrCode: integer);

  end;

EMyCompoRangeError =class(EMyComponentError);

EMyCompoInvalidValue =class(EMyComponentError);

TForm1 =class(TForm)

  Button1: TButton;

  Button3: TButton;

  Button2: TButton;

  Button4: TButton;

  Button5: TButton;

  ListBox1: TListBox;

  Button6: TButton;

  Button7: TButton;

  Button8: TButton;

  BitBtn1: TBitBtn;

procedure Button1Click(Sender: TObject);

  procedure Button3Click(Sender: TObject);

  procedure Button2Click(Sender: TObject);

  procedure Button4Click(Sender: TObject);

  procedure Button5Click(Sender: TObject);

  procedure Button6Click(Sender: TObject);

  procedure Button7Click(Sender: TObject);

  procedure Button8Click(Sender: TObject);

  procedure BitBtn1Click(Sender: TObject);

  private

 

  public

 

  end;

var

Form1 :TForm1;

Stream :TMemoryStream;

implementation

// Rutinele care urmeaza sunt scrise utilizand

// maniera Delphi de tratare a exceptiilor

function CharFromString(sVal: string; iPos: integer): char;

begin

if iPos > Length(sVal) then

Raise Exception.Create('Out of Range');

result := sVal[iPos]

end

procedure InsertChar(cVal: char; var sVal: string; iPos: integer);

begin

if iPos > Length(sVal) then

Raise Exception.Create('Out of Range');

sVal[iPos] := cVal;

end

procedure UseFunctions;

var cVal: char;

sStrVal: string;

begin

try

sStrVal := 'Delphi Rock ';

cVal := CharFromString(sStrVal,13);

if cVal <> 's' then

InsertChar('s',sStrVal,12);

ShowMessage(sStrVal);

except



exit;

end;

end

procedure TForm1.Button1Click(Sender: TObject);

begin

UseFunctions;

end

// Aceste rutine rezolva aceleasi probleme ca

// mai sus intr-un stil de programare defensiv

// clasic.

function CharFromString(sVal: string; iPos: integer): char;

begin

Result := #0;

if iPos <= Length(sVal) then

result := sVal[iPos]

end

function InsertChar(cVal: char; var sVal: string; iPos: integer): boolean;

begin

Result := False;

if iPos <= Length(sVal) then

begin

sVal[iPos] := cVal;

Result := True;

end;

end

procedure UseFunctions;

var cVal: char;

sStrVal: string;

begin

sStrVal := 'Delphi Rock ';

cVal := CharFromString(sStrVal,12);

if cVal <> #0 then

begin

if cVal <> 's' then

if InsertChar('s',sStrVal,12) then

ShowMessage(sStrVal)

else

exit;

end

else

exit;

end

// Aceste rutine exemplifica utilizarea optionala

// a sintaxei [on..do] a unei constructii [try..except]

procedure LowMemTerminate;

begin

Application.Terminate;

end

procedure TForm1.Button2Click(Sender: TObject);

var pVal: PChar;

begin

try

GetMem(pVal,sizeof(Stream.Memory^));

StrLCopy(pVal,Stream.Memory,sizeof(Stream.Memory^)+1);

except

On E: EOutOfMemory do

LowMemTerminate;

On E: EAccessViolation do

begin

if MessageDlg(E.Message+': Terminate the program?',

mtError,[mbYes,mbNo],0) = mrYes then

Application.Terminate

end

else

Raise;

end;

end

procedure TForm1.Button3Click(Sender: TObject);

var pVal: PChar;

begin

try

GetMem(pVal,sizeof(Stream.Memory^));

StrLCopy(pVal,Stream.Memory,sizeof(Stream.Memory^)+1);

except

On E: Exception do

begin

if E is EOutOfMemory then

LowMemTerminate;

if E is EAccessViolation then

begin

if MessageDlg(E.Message+': Terminate the program?',

mtError,[mbYes,mbNo],0) = mrYes then

Application.Terminate;

end

else

Raise;

end;

end;

end

// Imbricare constructii [try..except] si [try..finally]

procedure TForm1.Button4Click(Sender: TObject);

var sVar: string;

pVar: PChar;

begin

try

GetMem(pVar,10);

try

StrCopy(pVar,'ListBox');

with ListBox1.Items do

begin

Add('Line1 - index 0');

Add('Line2 - index 1');

end;

sVar := ListBox1.Items[2];

finally

FreeMem(pVar,10);

end;

except

on EStringListError do

MessageDlg('List index out of bounds', mtError, [mbOk], 0);

on EAccessViolation do

MessageDlg('Memory Overwrite', mtError, [mbOk], 0);

else

Raise;

end;

end

procedure TForm1.Button5Click(Sender: TObject);

var sVar: string;

pVar: PChar;

begin

GetMem(pVar,10);

try

StrCopy(pVar,'ListBox');

try

sVar := ListBox1.Items[0];

except

on EStringListError do

begin

ListBox1.Items.Add('Item1');

sVar := ListBox1.Items[0];

end

else Raise;

end;

finally

FreeMem(pVar,10);

end;

end

// Aceste rutine arata utilizarea unei instantede tip EAbort

// [Silent Exception]

var Delphi: string;

procedure SetDelphiVariable(sValue: string);

begin

if Delphi = sValue then

Raise EAbort.Create('');

if (Length(sValue) > 0) and (Length(sValue) < 50) then

Delphi := sValue;

end

procedure TForm1.Button6Click(Sender: TObject);

begin

SetDelphiVariable('Anders Hejlsberg');

end

// These routines demonstrate the use of raising an

// exception of type EAbort - the silent exception

constructor EMyComponentError.Create(const Msg: string; ErrCode: integer);

begin

Inherited Create(Msg);

FErrorCode := ErrCode;

end

const

cInvalidValue = 0;

cRangeError = 1;

// These routines relate to the creation of custom exception

// types. Move statments into your global handler and

// replace "Sender" with EInstance to test

procedure TForm1.Button7Click(Sender: TObject);

begin

if Sender is EMyComponentError then

case (Sender as TCOmponent).Tag of

cInvalidValue: ;

cRangeError : ;

else

begin

ShowMessage('Fatal Error - Terminating program');

Application.Terminate;

end;

end;

end

procedure TForm1.Button8Click(Sender: TObject);

begin

if Sender is EMyComponentError then

begin

if Sender is EMyCompoRangeError then

else

if Sender is EMyCompoInvalidValue then

;

end

else

begin

ShowMessage('Fatal Error - Terminating program');

Application.Terminate;

end;

end

procedure TForm1.BitBtn1Click(Sender: TObject);

begin

Close

end;

end.




Document Info


Accesari: 1047
Apreciat: hand-up

Comenteaza documentul:

Nu esti inregistrat
Trebuie sa fii utilizator inregistrat pentru a putea comenta


Creaza cont nou

A fost util?

Daca documentul a fost util si crezi ca merita
sa adaugi un link catre el la tine in site


in pagina web a site-ului tau.




eCoduri.com - coduri postale, contabile, CAEN sau bancare

Politica de confidentialitate | Termenii si conditii de utilizare




Copyright © Contact (SCRIGROUP Int. 2025 )