Sunteți pe pagina 1din 31

Membri statici

versus membri de instanţă


• un membru de instanţă este orice membru dintr-o clasă care NU este
marcat ca static: câmpuri, proprietăți, metode
• un membru de instanţă poate fi utilizat numai după ce a fost creată o
instanță a clasei respective: acest lucru se datorează faptului că membrii de
instanţă aparțin obiectului, deci un obiect trebuie să existe în prelabil
• un mebru static se crează marcându-l cu cuvântul cheie static
• câmpuri de date statice: acest lucru înseamnă că toate instanţele claselor
respective împart acelaşi membru static, practic se alocǎ o singurǎ datǎ
memorie, o singură zonă comună tuturor obiectelor clasei; fiecare instanţǎ a
clasei are acces la copia unicǎ a datelor statice.
• proprietǎţile şi metodele pot fi la rândul lor declarate statice: acestea sunt
de regulǎ utilizate pentru a prelucra datele statice ale clasei
• un membru static este apelabil chiar și atunci când nu a fost creată nicio
instanță a clasei => accesat de numele clasei, nu prin numele unei instanţe
create în prealabil
Utilizarea membrilor statici (1)
• proprietǎţile şi metodele statice (inclusiv constructorii) prezintǎ dezavantajul
cǎ nu pot utiliza în cadrul implementǎrii decât câmpurile declarate statice
ale clasei din care fac parte, neavând acces la niciuna din datele instanţelor
clasei respective (dacǎ existǎ vreuna)
• în cazul constructorilor declaraţi static, aceştia sunt apelaţi înainte ca orice
membru static al clasei respective să fie referit, astfel încât aceştia pot fi
utilizaţi la iniţializarea clasei, nu doar a obiectelor; constructorii declaraţi
static nu pot avea parametri
• constructorii declaraţi static nu pot avea modificator de acces şi nu pot fi
supraȋncărcati; constructorul va fi executat doar o singură dată spre
deosebire de constructorii de instanţă care se execută la crearea fiecărei
instanţe a clasei => anumite câmpuri statice care trebuie iniţializate dintr-o
sursă externă înainte de prima utilizare a clasei (setări/configurări iniţiale)
• metodele statice pot fi supraîncărcate (overloadiing), dar nu suprascrise
(overriding), deoarece aparțin clasei și nu unei instanțăe a clasei
• o clasă non-statică poate conține metode statice, câmpuri, proprietăți sau
evenimente
Utilizarea membrilor statici (2)
• membri statici se caracterizeazǎ deci prin faptul cǎ aparţin clasei propriu-
zise şi nu unui obiect al unei anumite clase => datele statice pot fi iniţializate
chiar dacā nu existǎ încǎ obiecte instanţiate, prin intermediul clasei; se
aplicǎ regulile generale de acces.
nume_clasa.membru_static
nume_clasa.nume_metoda_statica
• există clase, precum clasa System.Math, care conţin numai membri statici
• o clasa poate fi declaratǎ ca fiind staticǎ:
– toti membrii clasei trebuie sǎ fie statici (fie ca e vorba de campuri, proprietati sau
metode)
– clasa nu mai poate fi instanțiatǎ folosind new()
– nu se pot defini constructori de instanțǎ (doar constructori statici)
– clasa nu poate fi derivatǎ
• declararea unor membri statici este utilă, deoarece ea reprezintă soluţia
optimă în cazul în care obiectele unei clase folosesc date în comun,
reducîndu-se astfel numărul de variabile globale.
• utilizarea membrilor statici rezolvǎ numeroase situaţii în programare, însǎ
trebuie folosiţi cu precauţie
Exemplu (1)
internal class Punct
{
public int X { get; set; }
public int Y { get; set; }
public static Punct Centru { get; set; } = new Punct(0, 0);
public Punct()
{ }
public Punct(int x, int y)
{
this.X = x; this.Y = y;
}
//membru (metoda) de instanta
public int DistantaLaPatrat()
{
int distx = Centru.X - X; int disty = Centru.Y - Y;
return (distx * distx) + (disty * disty);
}
public static void ModificaCentru(int xc, int yc)
{
Centru.X = xc; Centru.Y = yc;
}
}
Exemplu (2)
Punct testpt = new Punct(5, 7);

//calcul distanta fata de centrul (0,0)


Console.WriteLine("Distanta la patrat fata de centru =
"+testpt.DistantaLaPatrat());

//modificare valoare camp static utilizand proprietati


Punct.Centru.X = 2;
Punct.Centru.Y = 2;
//calcul distanta fata de (2,2)
Console.WriteLine("Distanta la patrat fata de centru = " +
testpt.DistantaLaPatrat());

//modificare camp static prin intermediul metodei statice


Punct.ModificaCentru(3, 4);
//calcul distanta fata de (3,4)
Console.WriteLine("Distanta la patrat fata de centru = " +
testpt.DistantaLaPatrat());
This
• cuvântul cheie this este o variabilă locală care apartine oricarei instanţe ne-
statice a unui obiect şi reprezintă o referinţǎ spre obiectul însuşi; în
consecinţă this are sens şi poate apǎrea numai în definiţia unei metode sau
proprietǎţi non-statice definite în cadrul unei clase
• this nu necesită declarare şi rareori este referit in mod explicit; el este
utilizat în mod implicit pentru referinte catre membrii obiectului şi conţine
adresa instanţei curente a obiectului respectiv
• referirea la membri unui obiect prin intermediul lui this se poate face din
interiorul clasei prin:
this.metoda sau this.proprietatea
Moştenirea şi ierarhia de clase –
concepte de bază
• moştenirea reprezintă mecanismul care • la nivel de clase, C# suportă numai
permite crearea unei ierarhii de obiecte moştenire simplă: acest lucru
cu descendenţi, care moştenesc implică faptul că o clasă poate să fie
derivată dintr-o singură clasă de
accesul şi structurile de date ale bază
strămoşilor.
• prin intermediul moştenirii se pot X = clasa
reutiliza şi extinde clasele existente, de baza (parinte)
fără a rescrie codul original; diferenţa
fundamentală între limbajele de Partea mostenita
programare procedurale şi cele de la X
orientate pe obiecte o reprezintă tocmai Y = clasa
utilizarea conceptului de moştenire derivata din X
Partea specifica
(copil)
lui Y
• în programarea obiectuală se admite
compatibilitatea între tipul clasei
derivate şi tipul clasei de bază,
reciproca nefiind însă adevărată
Modificatorii abstract şi sealed
• obligă respectiv se opun procesului de moştenire
• o clasă declarată abstractă (abstract) trebuie neapărat derivată, pentru că
ea însăşi nu poate fi instanţiată
abstract class Clasa_abstracta
{ ... }

• o clasă declarată ca sigilată (sealed) nu mai poate fi derivată ulterior,


practic ea trebuie văzută ca o clasă terminală din cadrul ierarhiei; derivarea
unei clase dintr-o clasă sigilată, compilatorul va genera o eroare
sealed class Clasa_terminala
{ ... }

• o metodă declarată abstractă nu are implementare (corp) şi trebuie


redefinită (override) în toate clasele non-abstracte derivate din clasa din
care face parte metoda
Moştenirea şi apelul constructorilor
• întotdeauna clasa de bază este instanţiată înaintea clasei derivate:
constructorul clasei de bază este apelat înaintea celui din clasa
derivată => lanţ de apeluri
• întotdeauna la crearea unui obiect dintr-o clasă derivată se apeleaza
întâi constructorul clasei de bază
• dacă nu se specifică nicio clasă de bază în definirea unei clase, implicit
aceasta se consideră derivată din clasa de bază System.Object =>
toate clasele din C# şi .NET sunt derivate implicit din System.Object
sau dintr-o clasǎ derivatǎ din clasa Object

https://learn.microsoft.com/en-us/dotnet/api/system.object?view=net-6.0
Exemplu - clasa Baza
Baza
internal class Baza
{
public int? Camp_Baza { get; set; }
public Baza() Derivata
{
Camp_Baza = 0;
Console.WriteLine("Constructorul clasei Baza fara parametru");
}
public Baza(int p)
{
Camp_Baza = p;
Console.WriteLine("Constructorul clasei Baza cu parametru int {0} ", p);
}
public void Afisare() => Console.WriteLine("Clasa Baza cu parametrul
Camp_Baza {0}", Camp_Baza);
public void Metoda_Baza() => Console.WriteLine("Metoda proprie a clasei Baza");
}
Exemplu - clasa Derivata
internal class Derivata:Baza
{
int? Camp_Derivata { get; set; }
public Derivata()
{
Camp_Derivata = 0;
Console.WriteLine("Constructorul clasei Derivata fara parametru");
}
public Derivata(int b, int d) : base(b)
{
Camp_Derivata = d;
Console.WriteLine("Constructorul clasei Derivata
cu parametri {0} {1}", b,d);
}
public void Afisare()
{
base.Afisare();
Console.WriteLine("Clasa derivata cu Camp_Derivata {0}", Camp_Derivata);
}
public void Metoda_Derivata() => Console.WriteLine("Metoda proprie
a clasei Derivata");
}
Exemplu – Main
//cream obiecte
Baza obj_baza1 = new Baza();
Baza obj_baza2 = new Baza(5);
Derivata obj_deriv1 = new Derivata();
Derivata obj_deriv2 = new Derivata(7, 8);

Console.WriteLine();
//apelam metode
obj_baza2.Afisare();
obj_deriv2.Afisare();
obj_deriv1.Metoda_Derivata();
obj_deriv1.Metoda_Baza();

//?? care afisare?


Console.WriteLine();
Baza obj_baza3 = new Derivata(10, 15);
obj_baza3.Afisare();
Moştenirea şi implementarea
constructorilor
• deoarece scopul claselor derivate este acela de a adăuga noi caracteristici
claselor de bază, în mod evident constructorii acestora sunt mai complecşi
• abordarea utilizată în acest sens este ca aceştia să apeleze în mod
implicit sau explicit constructorii claselor de bază ori de cîte ori este posibil
• regula este următoarea: în cazul constructorilor, se apelează mai întîi
constructorii claselor de bază, apoi se execută acţiuni specifice
constructorului clasei derivate.

Punct

Patrat Cerc
Dreptunghi
Exemplu – clasa Punct
internal class Punct
{
//proprietatea X
public int X { get; set; }
//proprietatea Y
public int Y { get; set; }
//constructori pentru clasa Punct
public Punct()
{ }
public Punct(int x, int y)
{
this.X = x;
this.Y = y;
}
//metoda cu acelasi nume!!!
public void Deseneaza() => Console.WriteLine("Coordonatele punctului
desenat sunt: x={0} , y={1}", this.X, this.Y);
}
Exemplu – clasa Patrat
internal class Patrat:Punct
{
public int Latura { get; set; }
//constructori pentru clasa Patrat
public Patrat()
{ }
public Patrat
(int x, int y, int latura) : base(x, y)
{
this.Latura = latura;
}
//metoda cu acelasi nume!!
public void Deseneaza()
=> Console.WriteLine("Coordonatele patratului desenat sunt:
x={0} , y={1}, latura={2}\n", this.X, this.Y, this.Latura);

}
Exemplu – clasa Dreptunghi
internal class Dreptunghi:Punct
{
public int Lungime { get; set; }
public int Latime { get; set; }
//constructori pentru clasa Dreptunghi
public Dreptunghi()
{ }
public Dreptunghi(int x, int y, int lungime, int latime) : base(x, y)
{
this.Lungime = lungime;
this.Latime = latime;
}
//metoda cu acelasi nume!!
public void Deseneaza()
=> Console.WriteLine("Coordonatele dreptunghiului desenat sunt:
x={0} , y={1}, lungime={2} latime={3}\n",
this.X, this.Y, this.Lungime, this.Latime);
}
Exemplu – clasa Cerc
internal class Cerc:Punct
{
public int Raza { get; set; }
public Cerc()
{ }
public Cerc(int x, int y, int raza) : base(x, y)
{
this.Raza = raza;
}
//metoda cu acelasi nume!!
public void Deseneaza()
=> Console.WriteLine("Coordonatele cercului desenat sunt:
x={0} , y={1}, raza={2}\n",
this.X, this.Y, this.Raza);
}
Exemplu – Main
//cream obiecte
//apel implicit la constructorul fara parametru al clasei Punct
Patrat p0 = new Patrat();
Cerc c0 = new Cerc();
Dreptunghi d0 = new Dreptunghi();

//apel explicit la constructorul cu parametru al clasei Punct


Patrat p = new Patrat(8, 3, 20);
Cerc c = new Cerc(7, 10, 40);
Dreptunghi d = new Dreptunghi(2, 7, 30, 50);

//apel metode cu acelasi nume ??


p.Deseneaza();
c.Deseneaza();
d.Deseneaza();
Polimorfismul
Polimorfismul => capacitatea unui obiect de a se comporta ca şi
un obiect de alt tip, sau abilitatea unei metode cu acelasi nume de
a desfǎşura acțiuni diferite, functie de contextul în care este
apelatǎ sau de clasa derivatǎ în care se aflǎ.
– Polimorfism de tip: utilizarea unui obiect de un anumit tip
(de regulă un obiect derivat) ca şi cum ar fi de un alt tip (de
regulă clasa de bază din care derivǎ)
– Polimorfism de metodă: redefinirea comportamentului
unei metode într-o clasă derivatǎ (prin mostenire) sau într-o
alta clasǎ (prin implementare interfațǎ => implementări
diferite pentru metodele care sunt apelate cu acelaşi nume.
Mecanismul polimorfismului (1)
class Baza
• mecanismul care stă la baza {
polimorfismului îl reprezintă public void Metoda_Baza() { ... }
posibilitatea de a referi obiecte- public void Metoda_Comuna() { ... }
derivate prin intermediul unor referinţe }
către clasa de bază => este corectă class Derivata: Baza
asignarea: {
public void Metoda_Derivata() { ...
Baza b = new Derivata(); }
public void Metoda_Comuna() { ... }
• obiectul de tip Derivata este tratat ca }
un obiect de tip Baza, ceea ce este
• dacă însă se încearcă accesul la metoda
corect întrucît Derivata este un sub-
comună a celor două clase, compilatorul va
tip sau tip derivat a lui Baza:
genera un warning prin care ne atenţionează
b.Metoda_Baza(); //corect că Metoda_comuna din Derivata ascunde
b.Metoda_Derivata(); //eroare Metoda_comuna moştenita de la clasa
Baza.
• accesul la metoda proprie a clasei
Baza este corect; în schimb, metoda • in acest caz, se va afişa totuşi metoda
proprie a clasei Derivata nu este Metoda_comuna a clasei Baza:
accesibilă deoarece b este tratat ca Baza b = new Derivata();
fiind de tip Baza. b.Metoda_Comuna();
Mecanismul polimorfismului (2)
class Derivata: Baza class Baza
{ {
public void Metoda_Derivata() public void Metoda_Baza()
{ ... } { ... }
public override void public virtual void
Metoda_Comuna() { ... } Metoda_Comuna() { ... }
} }
• în cazul metodelor virtuale definite în class Derivata: Baza
cadrul claselor de bază şi redefinite cu {
override în cazul claselor derivate, public void Metoda_Derivata()
metoda din clasa de bază este { ... }
suprascrisa în cadrul clasei derivate =>
compilatorul va aplica legarea dinamică public new void Metoda_Comuna()
(dynamic binding) şi în consecinţă va { ... }
“vedea” tipul obiectului numai în }
momentul execuţiei
• CLR (Common Language Runtime) va • utilizarea lui new în loc de override în
considera în acest caz tipul obiectului cu exemplul anterior ar însemna cǎ
care a fost asignată referinţa în momentul metoda din clasa derivatǎ este nouǎ,
execuţiei si nu tipului de care a fost aşa cǎ este ascunsǎ dacǎ este
declarată referinţa => se va apela apelatǎ prin intermediul unui pointer la
metoda corespunzătoare clasei Derivata clasa de bazǎ => se va apela metoda
=> comportament polimorfic din clasa Baza
Baza b = new Derivata(); Baza b = new Derivata();
b.Metoda_Comuna(); b.Metoda_Comuna();
Mecanismul polimorfismului (3)
• reprezintă concept fundamental în programarea orientată pe obiecte
alături de încapsulare şi moştenire
• ideea polimorfismului în acest context (care, în sens etimologic al
cuvȃntului înseamnă mai multe forme) porneşte de la faptul că este
posibilă apelarea metodelor claselor derivate prin intermediul unei
referinţe la clasa de bază, în momentul execuţiei
• conform definiţiei, polimorfismul reprezintă “abilitatea claselor de a furniza
implementări diferite pentru metodele care sunt apelate cu acelaşi nume”
=> se bazează pe utilizarea metodelor virtuale şi redefinirea acestora
în clasele derivate cu override (moştenire)
• metodele abstracte sunt implicit virtuale => redefinirea (suprascrierea)
acestora în clasele derivate se realizează tot cu overrride
• conceptul de virtual se aplică doar metodelor de instanţă nu şi
metotodelor statice
Mecanismul polimorfismului (4)
• metodele declarate virtuale sau abstracte stau la baza polimorfismului în
programarea orientată pe obiecte => decizia privind care metodă va fi
efectiv apelată este întârziată şi are loc doar în momentul execuţiei
(runtime) iar selecţia metodei se face în aces caz pe baza tipului existent
din momentul execuţiei şi nu pe baza celui declarat în momentul
compilării
• din considerente de performanţă, metodele în C# nu sunt toate virtuale în
mod implicit
• până la versiunea C#9 exista o regulă prin care se impunea ca
semnătura metodelor redefinite cu override să fie identică cu cea a
metodei pe care o redefinesc din clasa de bază; începând cu C#9
această cerinţă a limbajului s-a mai relaxat în sensul că tipul valorii
returnate de metodă poate fi identic sau derivat din tipul declarat la clasa
de bază
Polimorfismul si conversiile de tip
• conversii de la tipul de bază către cel derivat (down-casting) şi invers
(up-casting).
• conversia de tip de la tipul derivat către bază (up-casting) este sigură,
simplă şi implicită:
Baza b = new Derivata1(); //conversie implicita up-casting
Baza b = new Derivata2();
• conversia de la bază către tipul derivat (down-casting) nu este sigură (în
sensul că pot apărea excepţii dacă se referă ulterior, de exemplu, un
membru propriu al clasei derivate care nu mai este accesibil deoarece în
urma conversiei obiectul este tratat ca fiind de tipul de bază) şi trebuie
realizată explicit; chiar şi atunci conversia poate să nu fie realizabilă,
datorită incompatibilităţii între tipuri:
Baza [] b = {new Derivata1(), new Derivata2()};
//corect dar nesigur
Derivata1 d = (Derivata1) b[0];
//exceptie - InvalidCastException
Derivata1 d1 = (Derivata1) b[1];
Operatorii is si as pentru testarea
tipului obiectelor
• verificarea tipurilor utilizând is:
Console.WriteLine (b[0] is Derivata1); //returneaza true
Console.WriteLine (b[1] is Derivata1); //returneaza false
• verificarea tipurilor utilizând as:

Baza [] b = {new Derivata1(), new Derivata2()};


Derivata1 d1 = b[1] as Derivata1;
if (d1 != null)
Console.WriteLine (Conversie de tip corecta!);
else
Console.WriteLine(Conversie de tip incorecta!);
• chiar dacă prezintă o funcţionalitate asemănătoare, is nu face decît să
verifice tipul în momentul execuţiei pe când as, în plus, realizează şi
conversia către tipul specificat.
Exemplu – clasa Punct
internal class Punct
{
//proprietatea X
public int X { get; set; }
//proprietatea Y
public int Y { get; set; }
//constructori pentru clasa Punct
public Punct()
{ }
public Punct(int x, int y)
{
this.X = x;
this.Y = y;
}
public virtual string IsA { get { return "Punct"; } }
public virtual void Deseneaza() => Console.WriteLine("Coordonatele
punctului desesenat sunt: x={0} , y={1}", this.X, this.Y);
}
Exemplu – clasa Patrat
internal class Patrat:Punct
{
public int Latura { get; set; }
//constructori pentru clasa Patrat
public Patrat()
{ }
public Patrat
(int x, int y, int latura) : base(x, y)
{
this.Latura = latura;
}
public override string IsA {get { return "Patrat"; }}
public override void Deseneaza()
=> Console.WriteLine("Coordonatele patratului desenat sunt:
x={0} , y={1}, latura={2}\n", this.X, this.Y, this.Latura);

}
Exemplu – clasa Dreptunghi
internal class Dreptunghi:Punct
{
public int Lungime { get; set; }
public int Latime { get; set; }
//constructori pentru clasa Dreptunghi
public Dreptunghi()
{ }
public Dreptunghi(int x, int y, int lungime, int latime) : base(x, y)
{
this.Lungime = lungime;
this.Latime = latime;
}
public override string IsA { get { return "Dreptunghi"; }}
public override void Deseneaza()
=> Console.WriteLine("Coordonatele dreptunghiului desenat sunt:
x={0} , y={1}, lungime={2} latime={3}\n",
this.X, this.Y, this.Lungime, this.Latime);
}
Exemplu – clasa Cerc
internal class Cerc:Punct
{
public int Raza { get; set; }
public Cerc()
{ }
public Cerc(int x, int y, int raza) : base(x, y)
{
this.Raza = raza;
}
public override string IsA { get { return “Cerc"; }}
public override void Deseneaza()
=> Console.WriteLine("Coordonatele cercului desenat sunt:
x={0} , y={1}, raza={2}\n",
this.X, this.Y, this.Raza);
}
Polimorfism - exemplu
//cream obiecte
Punct pt = new Punct(5, 7); Patrat patrat = new Patrat();
Cerc cerc = new Cerc(); Dreptunghi dreptunghi = new Dreptunghi();

//apel metode si proprietati => care?


pt.Deseneaza();
Console.WriteLine("Obiect din clasa "+pt.IsA);
patrat.Deseneaza();
Console.WriteLine("Obiect din clasa "+patrat.IsA);
dreptunghi.Deseneaza();
Console.WriteLine("Obiect din clasa " + dreptunghi.IsA);

//polimorfism => care metoda Deseneaza va fi apelata?


Punct p;
p = new Patrat(8, 3, 20);
p.Deseneaza();

p = new Cerc(7, 10, 40);


p.Deseneaza();

p = new Dreptunghi(2, 7, 30, 50);


p.Deseneaza();
Concluzii - polimorfism
• dacǎ dorim sǎ redefinim o metodǎ definitǎ într-o clasǎ de bazǎ ca virtualǎ în
cadrul claselor derivate, aceasta trebuie marcatǎ cu cuvintele cheie
override sau new
• override înseamnǎ cǎ metoda din clasa derivatǎ trebuie sǎ anuleze metoda
din clasa de bazǎ, ceea ce conduce la un comportament polimorfic
• utilizarea lui new în loc de override în exemplul anterior ar însemna cǎ
metoda din clasa derivatǎ este nouǎ, aşa cǎ este ascunsǎ dacǎ este
apelatǎ prin intermediul unui pointer la clasa de bazǎ
• obtinerea polimorfismului implica legarea dinamicǎ (dynamic binding) care
este realizatǎ doar în faza de execuţie a programului, şi selecţia metodei
efectiv apelate se realizeazǎ pe baza tipului cu care a fost asignat efectiv
obiectul în momentul execuţiei
• mecanismul funcţiilor virtuale/abstracte asigurǎ un comportament polimorfic
al metodelor definite virtuale/abstracte în cadrul unor clase de bazǎ şi
redefinite în cadrul claselor derivate cu override, atunci când acestea sunt
apelate prin intermediul unor referinţe cǎtre clasa de bazǎ

S-ar putea să vă placă și