Sunteți pe pagina 1din 10

Programare orientată pe obiecte Curs 10

Supraîncărcarea operatorilor

La fel ca in C++ operatorii pot fi supraîncărcați însă pe lângă asemănări sunt și unele
diferențe.
Sintaxa:
public static tip_rez operator op(tip parametru)
{ …}
public static tip_rez operator op(tip1 parametru1, tip2
parametru2)
{ …}

 tip_rez reprezintă tipul valorii întoarse de operația op. Valoarea intoarsă poate fi
de orice tip, însa adeseori este de acelasi tip cu clasa pentru care are loc
supraincarcarea operatorului;
 în cazul operatorului unar, parametru trebuie sa fie de același tip cu clasa pentru
care se redefinește operatorul. În cazul operatorului binar, cel putin unul din
operanzi (parametru1sau parametru2) trebuie sa fie de acelasi tip cu clasa
pentru care se redefineste operatorul.
 parametrii operatorilor nu pot utiliza modificatorii ref și out.

Important: Există o restricție importantă referioare la redefinirea operatorilor relaționali


(ex.: ==, <, <= etc) și anume aceea că trebuie redefiniți în perechi. Adică, dacă este
redefinit operatorul < atunci trebuie redefinit și operatorul >.
Există operatori care nu pot fi supraincarcati: &&, ||, [ ], ( ), new, is,
sizeof, ?,. =, +=, -=.

Supraîncărcarea operatorilor poate fi urmărită în exemplul următor.

Exemplu:
using System;

class Complex{
double re, im;

//constructori
public Complex(double re=0, double im=0)
{
this.re=re;
this.im=im;
}
public Complex(Complex z)
{
re=z.re;
im=z.im;
}

1 lect. dr. Marius Apetrii


Programare orientată pe obiecte Curs 10

public Complex(String str)//constructor folosit la conversii din expresii de


tipul "a+bi"
{
int pos_plus = str.IndexOf('+');
int pos_minus = str.IndexOf('-');
if(pos_plus<0){
re = Convert.ToDouble(str.Substring(0,pos_minus));
im = Convert.ToDouble(str.Replace("i", "").Substring(pos_minus));
}
else if(pos_minus<0){
re = Convert.ToDouble(str.Substring(0,pos_plus));
im=Convert.ToDouble(str.Replace("i","").Substring(pos_plus+1));
}
else{
re =
Convert.ToDouble(str.Substring(0,pos_plus>pos_minus?pos_plus:pos_minus));
im=Convert.ToDouble
(str.Replace("i","").Substring(pos_plus>pos_minus?pos_plus:pos_minus));
}
}
//metode
public double modul()
{
return Math.Sqrt(re*re+im*im);
}
public double argument()
{
return Math.Atan2(im,re);
}
public double Re
{
get{return re;}
set{re=value;}
}
public double Im
{
get{return im;}
set{im=value;}
}
//supraincarcare operatori
public static Complex operator+(Complex z1,Complex z2)
{
return new Complex(z1.re+z2.re,z1.im+z2.im);
}
public static Complex operator-(Complex z1,Complex z2)
{
return new Complex(z1.re-z2.re,z1.im-z2.im);
}
public static Complex operator*(Complex z1,Complex z2)
{
return new Complex(z1.re*z2.re-z1.im*z2.im,z1.re*z2.im+z1.im*z2.re);
}
public static Complex operator/(Complex z1,Complex z2)
{
double t=z2.re*z2.re+z2.im*z2.im;
return new Complex((z1.re*z2.re+z1.im*z2.im)/t ,(z1.im*z2.re-
z1.re*z2.im)/t);
}

2 lect. dr. Marius Apetrii


Programare orientată pe obiecte Curs 10

public static bool operator==(Complex z1,Complex z2)


{
return z1.re==z2.re && z1.im==z2.im;
}
public static bool operator!=(Complex z1,Complex z2)
{
return z1.re!=z2.re || z1.im!=z2.im;
}
public static Complex operator-(Complex z)
{
return new Complex(-z.re,-z.im);
}
public static Complex operator~(Complex z)//conjugat
{
return new Complex(z.re,-z.im);
}
public static Complex operator++(Complex z)
{
return new Complex(z.re+1,z.im);
}
public static implicit operator double(Complex z)//pt. conversie implicita
{
return z.re;
}
public static explicit operator int(Complex z)//pt. conversie explicita
{
return (int)z.re;
}
public static implicit operator Complex(double d)//pt. conversie implicita
{
return new Complex(d);
}
public static explicit operator Complex(String str)//pt. conversie explicita
{
return new Complex(str);
}
}

static void Main(string[] args)


{
double r=5;
Complex c=new Complex(r,9);//constructor
Complex z=new Complex(c);//constructor copiere
r=c;//operator conversie
c = 5;//operator conversie
z=++c+5/z++;
c = (Complex)"7+5.2i";//operator conversie
r=(int)c;
}

3 lect. dr. Marius Apetrii


Programare orientată pe obiecte Curs 10

Transmiterea parametrilor

Pentru transmiterea parametrilor către metode avem la dispoziție: transferul prin valoare și
transferul prin referinta. În mod implicit, tipurile valorice sunt transferate metodelor prin
valoare, în timp ce obiectele sunt transferate prin referință.
-transferul prin valoare: Metoda copiază valoarea parametrului efectiv în parametrul
formal al subrutinei. Modificarile aduse parametrului subrutinei nu vor modifica valoarea
parametrului efectiv.
-transferul prin referinta: Se transmite parametrului formal o referință a parametrului
efectiv și nu valoarea acestuia. În interiorul subrutinei, referința este utilizată pentru accesul
la parametrul efectiv. Modificarile parametrului formal vor afecta și parametrul efectiv.

Modificatorii ref și out

În mod implicit tipurile valorice sunt transferate catre metode prin valoare. Acest
comportament poate fi modificat cu ajutorul cuvintelor cheie ref si out.
Modificatorul ref:
 se utilizeaza atunci când se dorește ca o anumită metodă să modifice parametrii
efectivi, forțează transferul prin referință în detrimentul transferului prin valoare;
 apare atât în declarație cât și în apelul metodei. Parametrul transferat cu ref trebuie
sa aiba o valoare atribuita inainte de apel.

Modificatorul out:
 se utilizează atunci când se dorește întoarcerea de către metodă a mai multor valori
mediului apelant. O instructiune return întoarece o singura valoare. Dacă se dorește
întoarcerea spre exemplu a doua valori atunci problema se rezolva cu ajutorul
modificatorului out.
 apare atât în declarație cât și în apelul metodei. Nu este necesar ca variabila utilizată
ca parametru out să fie inițializată înainte de apelul metodei.

Exemplu:
class OClasa
{
protected internal int val;
public OClasa(int val)
{
this.val=val;
}
public int Val
{
get { return val; }
set { val = value; }
}
}
class Program
{
public static void Schimba(int i)

4 lect. dr. Marius Apetrii


Programare orientată pe obiecte Curs 10

{
i=100;
}
public static void Schimba(ref int i)
{
i = 100;
}
public static void Schimba(OClasa i)
{
i.val = 100;//recunoscut deoarece val este "protected internal"
}
public static void Schimba(int[] i)
{
i[0]=100;
}
public static void Schimba(List<OClasa> i)
{
i[0].Val=100;
}
public static void Calcul(int x,int y,out int S,out int P)
{
S = x + y;
P = x * y;
}
static void Main(string[] args)
{
int i=1,j=2,suma,produs;
OClasa o = new OClasa(1);
int[] t = {1};
List<OClasa> l = new List<OClasa>();
l.Add(new OClasa(1));
Schimba(i);
Schimba(ref j);
Schimba(o);
Schimba(t);
Schimba(l);
Calcul(i, j, out suma,out produs);
Console.WriteLine(i);
Console.WriteLine(j);
Console.WriteLine(o.Val);
Console.WriteLine(t[0]);
Console.WriteLine(l[0].Val);
Console.WriteLine("Suma: "+suma);
Console.WriteLine("Produs: "+produs);
}
}
În urma execuției obținem:
1
100
100
100
100
Suma: 101
Produs: 100
Press any key to continue . . .

5 lect. dr. Marius Apetrii


Programare orientată pe obiecte Curs 10

Moștenirea

În C# moștenirea este asemănătoară celei din C++, dar există și unele deosebiri. În
C++ clasele și structurile sunt practic identice în timp ce în C # ele sunt destul de diferite.
În C# clasele pot implementa orice număr de interfețe, dar nu pot face moștenire multiplă
(pot moșteni de la o singură clasă de bază). Se poate deriva doar cu public. Mai mult
decât atât, în C# structurile nu acceptă moștenire, și nu acceptă constructori expliciți (unul
este prevăzut în mod implicit).
Important: este disponibil un nou specificator de acces protected internal (membrii
sunt vizibili atat în clasele care moștenesc clasa în care sunt definiți acești membri cât și în
cadrul grupului de fișiere care formează asamblajul).
În C#, într-o clasa derivată, se poate utiliza cuvântul rezervat base pentru a apela
membrii suprascriși ai clasei de bază.

Cuvantul cheie base poate fi utilizat si oarecum similar cu this, referindu-se la


clasa de baza a clasei derivate pentru care se utilizeaza.
Sintaxă:
base.membru;
unde membru poate desemna atat o metoda cât și o variabilă.

În cazul ierarhiilor de clase pe mai multe cuvântul base referă întodeauna elementele din
clasa de bază cea mai apropiată.

Este posibil ca o clasă derivată să definească un membru al cărui nume să coincidă


cu numele unui membru din clasa de bază. În acest caz, membrul clasei de bază nu va fi
vizibil în clasa derivată. Din punct de vedere tehnic aceasta nu este o eroare, insa
compilatorul va genera un mesaj de avertisment care informeaza utilizatorul că un nume a
fost ascuns. Dacă întradevar se dorește ascunderea unui membru al clasei de bază atunci se
poate utiliza cuvântul cheie new pentru ca mesajul de avertizare să nu mai apară.
Cuvatul cheie base permite și accesul la variabilele sau metodele ascunse.

Metodele virtuale acționează ca și în C++ cu precizarea că la redefinirea metodei în


cadrul claselor derivate se utilizeaza modificatorul override. O metodă abstractă se
poate crea specificând modificatorul de tip abstract. La fel ca în C++, metodele
abstracte nu au corp și nu sunt implementate în clasa de bază. Metodele abstracte sunt în
mod implicit virtuale. În fapt, utilizarea ambilor modificatori virtual și abstract
genereaza eroare.

Pentru declararea unei metode abstracte se utilizeaza sintaxa:


public abstract tip nume(lista-parametri);

O clasa care contine o metodă abstractă trebuie declarată ea insăși abstractă, precedând
declaratia class cu specificatorul abstract. Deoarece clasele abstracte nu definesc

6 lect. dr. Marius Apetrii


Programare orientată pe obiecte Curs 10

implementari complete, nu se pot instanția. Încercarea de a crea un obiect cu ajutorul


operatorului new, genereaza eroare.
Atunci când o clasă derivată mostenește o clasă abstractă trebuie să implementeze
toate metodele abstracte din clasa de bază.
O interfaţă este o clasă în care toate funcţiile sunt pur virtuale (abstracte). Interfeţele
sunt utile pentru a defini funcţionalitatea diferitelor clase. Prin convenţie, numele
interfeţelor încep cu litera I, astfel difereţiindu-se mai uşor de clase. După ce a fost
definită, o interfaţă se poate implementa în orice clasă care acceptă funcţionalitatea definită
în interfaţă. Sintaxa pentru implementarea unei interfeţe este aceeaşi cu cea folosită pentru
extinderea unei clase de bază.

Pentru ca o clasă să nu poată fi moştenită, trebuie declarată drept clasă închisă,


folosind sealed.

Limbajul C# definește o clasă specială, numită object, care este clasa de bază implicită
pentru toate celelalte clase și pentru toate celelalte tipuri, inclusiv tipurile valorice. Din
punct de vedere tehnic, numele C# object este sinonim pentru System.Object, din
arhitectura .NET.
Clasa object defineste mai multe metode, disponibile pentru orice obiect, cum ar fi:

bool Equals (object) Determina daca obiectul apelant este acelasi cu cel referit
bool Determina daca parametrii refera acelasi obiect.
Equals(object,object)
string ToString() Intoarce un string care descrie obiectul
Finalize() Executa actiunile de distrugere a obiectului, anterioare
colectarii spatiului ocupat de acesta. Finalize() se
acceseaza prin intermediul destructorilor.

Exemplu:
using System;

abstract class clasaDeBazaAbstracta


{
protected int a;
public clasaDeBazaAbstracta(int a)
{
this.a = a;
}
public abstract void scrie();
}

class clasaDerivataA : clasaDeBazaAbstracta


{
protected int b;
public clasaDerivataA(int a, int b)
: base(a)
{
this.b = b;
}

7 lect. dr. Marius Apetrii


Programare orientată pe obiecte Curs 10

public override void scrie()


{
Console.WriteLine("Clasa derivata A");
}
}
sealed class clasaDerivataB : clasaDerivataA
{
new double a;//ascundem a din clasa de baza
public clasaDerivataB(double a, int b)
: base(0, b)
{
this.a = a;
this.b = b;
}
public override void scrie()
{
Console.WriteLine("Clasa derivata B");
Console.WriteLine("a="+a);
Console.WriteLine("in clasa de baza a=" + base.a);
}
}
class clasaDerivataC : clasaDerivataB{ }//eroare

static void Main(string[] args)


{
clasaDeBazaAbstracta ab = new clasaDeBazaAbstracta(2);//eroare
clasaDerivataA a = new clasaDerivataA(1, 2);
clasaDerivataB b = new clasaDerivataB(2.3, 5);
a.scrie();
b.scrie();
}

După execuție:
Clasa derivata A
Clasa derivata B
a=2,3
in clasa de baza a=0
Press any key to continue . . .

Determinarea tipului unui obiect


Pentru a efectua conversii (utilizând operatorul cast) sau pentru comparări este necesar să
cunoaștem tipul obiectelor.

O prima posibilitate de a determina tipul unui obiect este aceea de a utiliza metoda
GetType(), pe care toate clasele o moștenesc de la clasa object, în combinație cu
operatorul typeof().

Exemplu:
if (a.GetType() == typeof(clasaDerivataA))
{
Console.WriteLine("Abiectul \"a\" este instanta a clasei clasaDerivataA");
}

8 lect. dr. Marius Apetrii


Programare orientată pe obiecte Curs 10

else
{
Console.WriteLine("Abiectul \"a\" nu este instanta a clasei clasaDerivataA");
}

O altă posibilitate este de a utiliza operatorul is. Acest operator ne permite să determinăm
dacă un obiect este sau poate fi convertit într-un tip dat.
Sintaxă:
<operand> is <type>

 Dacă <type> este o clasă atunci rezultatul este true dacă <operand> este de
tipul acelei clase sau de tipul unei clase derivate din clasa <type> sau poate fi
împachetat in acel tip;
 Dacă <type> este o interfață atunci rezultatul este true dacă <operand> este
de acel tip sau dacă este de un tip care implementează acea interfață;
 Dacă <type> este un tip valoric atunci rezultatul este true daca <operand>
este de acel tip sau este de un tip care poate fi despachetat în acel tip.

Exemplu:
using System;
class Animal{
public virtual void scrie()
{
Console.WriteLine("Sunt din clasa Animal");
}
public static int da_numar_picioare(Animal animal){
if(animal is Pisica)return 4;
if(animal.GetType()==typeof(Pasare))return 2;
return -1;
}
}
class Pisica: Animal{
String nume;
public Pisica(String nume)
{
this.nume=nume;
}
public override void scrie(){
Console.WriteLine("Sunt din clasa Pisica si ma cheama {0}.",nume);
}
}
class Pasare: Animal{
String nume;
public Pasare(String nume)
{
this.nume=nume;
}
public override void scrie(){
Console.WriteLine("Sunt din clasa Pasare si ma cheama {0}.",nume);
}
}

9 lect. dr. Marius Apetrii


Programare orientată pe obiecte Curs 10

static void Main(string[] args)


{
Animal animal;
Pisica pisica=new Pisica("Tom");
Pasare pasare=new Pasare("Twetty");
animal=pasare;//corect, clasa Pasare mosteneste clasa Animal
pisica=(Pisica)pasare;//eroare, intre clasele Pisica si Pasare nu exista
legatura
Console.WriteLine(Animal.da_numar_picioare(animal));//afiseaza 2
}

10 lect. dr. Marius Apetrii

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