Sunteți pe pagina 1din 7

03.

Clase şi structuri
I. Clase - generalităţi
O clasă încapsulează date şi metodele care acţionează asupra acelor date.
Sintatic, o clasă se declară astfel:
[atribute] [modificatori de acces] class <nume> [:<clasa_de_bază>]
{
[definiţia_clasei]
} [;]
Modificatorii de acces specifică cât de vizibil/accesibil este un membru în afara
clasei în care este definit:
• public: accesibil oriunde în afara clasei
• protected: accesibil doar în clasele derivate
• private: inaccesibil în afara clasei
• internal: accesibil doar în unitatea de traducere curentă.
Modificatorul de protecţie implicit este private; pentru fiecare membru (spre
deosebire de C++) trebuie specificat explicit modificatorul de protecţie dorit.
Membrii unei clase pot fi:
• câmpuri (fields) – păstrează o valoare şi li se pot aplica modificatori precum
static, const, readonly;
• metode (methods) – secvenţe de cod;
• proprietăţi (properties) – metode care simulează comportamentul câmpurile (smart
fields);
• constante – câmpuri a căror valoare nu poate fi modificată;
• indexuri (indexers) – manipularea unui obiect ca şi cum ar fi un tablou (smart
array);
• evenimente (events) – C# utilizează şablonul de proiectare publish/subscribe din
MSMQ (Microsoft Message Queuing) şi modelul asincron COM+ pentru a furniza
aplicaţiilor posibilitatea de a executa asincron secvenţe de cod;
• operatori (operators) – supraîncărcarea operatorilor.
II. Constructori
În C++, operatorul new dicta locul în care obiectul era creat (free store). În C#,
new reprezintă singura modalitate de a crea obiecte, utilizând sintaxa:
<class> <obiect> = new <class> (argumente_constructor);
Astfel,
Clasa_Mea obiect;

creează, în C++, o instanţă în stivă; în C#, obiect este doar o referinţă neiniţializată!
Pentru a creea instanţa, declaraţia corectă este:
Clasa_Mea obiect = new Clasa_Mea();

Orice obiect este iniţializat automat prin execuţia unui constructor; în exemplul
anterior, este vorba de constructorul fără parametri, constructorul implicit. Un
constructor are acelaşi nume cu clasa şi nu returnează. Ca şi în C++, dacă clasa nu
este dotată cu nici un constructor, compilatorul C# generează automat un constructor
implicit pentru respectiva clasă.
Cu excepţia constructorilor System.Object, un constructor invocă, înaintea
execuţiei primei linii proprii de cod, constructorul clasei de bază. Dacă clasa de bază
posedă mai mulţi constructori, îl puteţi selecta pe cel dorit cu base(...). Dacă într-un
constructor doriţi să apelaţi o versiune supraîncărcată a aceluiaşi constructor, puteţi
face acest lucru cu this(...).
//fisier ctori.cs
//compilati cu: csc ctori.cs

namespace pnoro{

class Base{
public Base(){
System.Console.WriteLine("Base::c-tor implicit");
}
public Base(int i){
System.Console.WriteLine("Base::ctor i={0}", i);
}
};

class Derived: Base{


public Derived(){
//apeleaza Base()
System.Console.WriteLine("Derived::c-tor implicit");
}

public Derived(int i){


//apeleaza Base()
System.Console.WriteLine("Derived::c-tor i={0}", i);
}

2
public Derived (int i, int j): base(i+1){
//apeleaza base(int)
System.Console.WriteLine("Derived::c-tor i={0} j={1}", i,j);
}
public Derived (string s): this(10){
//apeleaza Derived(int)
System.Console.WriteLine("Derived::c-tor s={0}", s);
}
};

class aplicatie{
public static void Main(){
Derived d1 = new Derived();
Derived d2 = new Derived(10);
Derived d3 = new Derived(10, 20);
Derived d4 = new Derived("un sir...");
}
};
}

Executând acest program, obţinem:


Base::c-tor implicit
Derived::c-tor implicit
Base::c-tor implicit
Derived::c-tor i=10
Base::ctor i=11
Derived::c-tor i=10 j=20
Base::c-tor implicit
Derived::c-tor i=10
Derived::c-tor s=un sir...

III. Static, const şi readonly


Un câmp static (la nivel de clasă) este creat la încărcarea aplicaţiei ce conţine
clasa şi există de toată durata de execuţie. Implicit, câmpurile statice sunt iniţializate
cu 0; din acest motiv, static int i = 0; şi static int i; sunt echivalente.
//fisierul static1.cs
//compilati cu: csc static1.cs

namespace pnoro{

class Base{
public Base(int i){}
}

class Derived : Base{


int i;
public Derived():base(i){
i = 10;
}
}

class Aplicatie{
public static void Main(){
Derived d = new Derived();
}
};
}

3
C# stipulează că doar câmpurile statice pot fi utilizate pentru a apela explicit
constructorul clasei de bază; din acest motiv, compilând exemplul anterior, obţinem
următorul mesaj de eroare:
static1.cs(12,24): error CS0120: An object reference is required for the
nonstatic field, method, or property 'pnoro.Derived.i'

Mesajul de eroare poate fi înlăturat declarându-l pe i ca fiind static.


Dacă aveţi nevoie să transmiteţi constructorului clasei de bază informaţii pe
care le aflaţi doar la execuţie, iar constructorul clasei derivate nu posedă aceste
informaţii în lista sa de parametri, puteţi utiliza o metodă statică, precum în exemplul
următor:

//fisierul static2.cs
//compilati cu: csc static2.cs

namespace pnoro{

class Base{
public Base(int i){
System.Console.WriteLine("Base::c-tor i={0}", i);
}
}

class Derived : Base{


static int GetInformation(){
//obtine informatii la executie
return 1;
}
public Derived():base(GetInformation()){
System.Console.WriteLine("Derived::c-tor");
}
}

class Aplicatie{
public static void Main(){
Derived d = new Derived();
}
};
}

Un câmp constant se declară cu const şi este o valoare setată la compilare, dată


sub forma unui literal şi care nu poate fi modificată. Implicit, câmpurile constante
sunt statice! Cu alte cuvinte, vorbim de constante la nivel de clasă!
Dacă valoarea unei constante nu este cunoscută la compilare, se utilizează
campuri readonly; evident, valoarea unui astfel de câmp poate fi setată doar în
constructor.

4
//fisierul static3.cs
//compilati cu: csc static3.cs

namespace pnoro{

class MyClass{
public const int i = 10;
public readonly int j;
public MyClass(){
j=20;
}
}

class Aplicatie{
public static void Main(){
MyClass o = new MyClass();
System.Console.WriteLine("i={0} j={1}", MyClass.i, o.j);

}
};
}

Se observă utilizarea lui i prin intermediul numelui de clasă, în timp ce j este


utilizat prin intermediul instanţei. Se observă, de asemenea, că suntem obligaţi să
instanţiem MyClass pentru a putea folosi câmpul readonly; acest lucru este OK dacă
felul în care clasa este instanţiată determină valoarea câmpului readonly.
Cum s-ar putea obţine o constantă (statică) pe care să o iniţializăm la execuţie?
Se declară un câmp simultan static şi readonly! Pentru a iniţializa un câmp static şi
readonly se utilizează un constructor static; acesta este, prin definiţie, implicit public.

//fisierul static4.cs
//compilati cu: csc static4.cs

namespace pnoro{

class MyClass{
public const int i = 10;
public static readonly int j;

static MyClass(){ //constructor static!


j=20;
}
}

class Aplicatie{
public static void Main(){
System.Console.WriteLine("i={0} j={1}", MyClass.i, MyClass.j);

}
};
}

Se observă că MyClass nu mai trebuie instanţiată iar j este utilizat prin


intermediul numelui clasei.

5
IV. Moştenire
În C# nu există decât moştenire simplă; pentru a moşteni de la o clasă de bază
se utilizează următoarea sintaxă:
class <derivedClass>:<baseClass>
Dacă se doreşte ca o clasă să nu poată fi utilizată drept clasă de bază, ea se
declară utilizând modificatorul sealed. Pentru o astfel de clasă, compilatorul just-in-
time poate aplica anumite optimizări; în particular, poate transforma toate apelurile
de funcţii virtuale în apeluri nevirtuale!
Observaţie:
• Moştenirea multiplă poate fi simulată prin intermediul interfeţelor pe care o clasă
alege să le implementeze.
O clasă abstractă se declară cu modificatorul abstract şi trebuie să conţină
măcar o metodă abstractă; o astfel de clasă nu poate fi instanţiată. Clasele derivate se
obligă să le implementeze metodele abstracte; implicit, metodele abstracte sunt
virtuale, ceea ce însemnă că în clasele derivate trebuie utilizat modificatorul override
pentru a oferi implementări metodelor abstracte!

V. Structuri
Sintactic, o structură se defineşte astfel:
[atribute] [modificatori de acces] struct <nume> [:interfeţe]
{
[definiţia_structurii]
} [;]

struct RGB{
public int Red;
public int Green;
public int Blue;
};
RGB rgb;
rgb.Red = 0xFF;

Observaţii:
• D.p.d.v. intern, o structură este un tip valoare, ea fiind derivată direct din
System.ValueType;

6
• Structura rgb este alocată în momentul declarării şi deci nu trebuie instanţiată cu
operatorul new;
• Câmpurile nu pot fi iniţializate decât explicit, precum în exemplul anterior, sau
prin intermediul operatorului new:
RGB rgb = new RGB();
• Pentru structuri nu se pot defini constructori fără parametri.
• Structurile nu pot fi baze pentru alte clase sau structuri;
• Structurile nu pot moşteni alte clase sau structuri.

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