21.02.2015 Views

operator

operator

operator

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

Przeciażanie ˛ <strong>operator</strong>ów (odsłona druga)<br />

Bogdan Kreczmer<br />

ZPCiR IIAiR PWr<br />

pokój 307 budynek C3<br />

bogdan.kreczmer@pwr.wroc.pl<br />

Copyright c○2005–2008 Bogdan Kreczmer ⋆<br />

⋆ Niniejszy dokument zawiera materiały do wykładu na temat programowania obiektowego. Jest on udostępiony pod<br />

warunkiem wykorzystania wyłacznie ˛ do własnych prywatnych potrzeb i może on być kopiowany wyłacznie ˛ w całości, razem z<br />

niniejsza˛<br />

strona˛<br />

tytułowa.<br />

˛


1<br />

Operatory arytmetyczne, bitowe i logiczne (i nie tylko)<br />

Indeksowanie wskaźnik [ wyrażenie ]<br />

Wywołanie funkcji wyrażenie ( lista wyrażeń )<br />

Przyrostkowa inkrementacja l-wartość ++<br />

Przyrostkowa dekrementacja l-wartość - -<br />

Równy<br />

Nierówny<br />

Koniunkcja bitowa<br />

⇓<br />

wyrażenie == wyrażenie<br />

wyrażenie != wyrażenie<br />

wyrażenie & wyrażenie<br />

Przedrostkowa inkrementacja<br />

++ l-wartość<br />

Różnica symetryczna<br />

wyrażenie ˆwyrażenie<br />

Przedrostkowa dekrementacja<br />

- - l-wartość<br />

Alternatywa bitowa<br />

wyrażenie | wyrażenie<br />

Negacja bitowa<br />

∼wyrażenie<br />

Iloczyn logiczny<br />

wyrażenie && wyrażenie<br />

Negacja logiczna<br />

! wyrażenie<br />

Suma logiczna<br />

wyrażenie || wyrażenie<br />

Minus jednoargumentowy<br />

- wyrażenie<br />

Wyrażenie warunkowe<br />

wyrażenie ? wyr. : wyr.<br />

Plus jednoargumentowy<br />

+ wyrażenie<br />

Proste przypisanie<br />

l-wartość = wyrażenie<br />

Mnożenie<br />

wyrażenie ∗ wyrażenie<br />

Przemnóż i przypisz<br />

l-wartość ∗= wyrażenie<br />

Dzielenie<br />

wyrażenie / wyrażenie<br />

Podziel i przypisz<br />

l-wartość /= wyrażenie<br />

Modulo<br />

wyrażenie % wyrażenie<br />

Weź modulo i przypisz<br />

l-wartość %= wyrażenie<br />

Dodawanie<br />

wyrażenie + wyrażenie<br />

Dodaj i przypisz<br />

l-wartość += wyrażenie<br />

Odejmowanie<br />

wyrażenie - wyrażenie<br />

Odejmij i przypisz<br />

l-wartość -= wyrażenie<br />

Przesuwanie w lewo<br />

wyrażenie >= wyr.<br />

Mniejszy<br />

wyrażenie < wyrażenie<br />

Koniunkcja bitowa i przypisz<br />

l-wartość &= wyrażenie<br />

Mniejszy lub równy<br />

wyrażenie wyrażenie<br />

wyrażenie >= wyrażenie<br />

⇓<br />

Różnica bitowa i przypisz l-wartość ˆ= wyrażenie<br />

Operatory zawarte w tej samej części tabeli maja˛<br />

ten<br />

sam priorytet.<br />

Przeciażanie ˛ <strong>operator</strong>ów (odsłona druga)


Operator przypisania<br />

2<br />

class LZespolona { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

public :<br />

float re, im;<br />

}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

int main( )<br />

{<br />

LZespolona Z1, Z2, Z3, Z4;<br />

}<br />

Z1 ❤ ✭✭✭✭✭✭ ❤❤❤❤❤ = 0;<br />

Z1 = Z2 = Z3 = Z4;<br />

Przeciażanie ˛ <strong>operator</strong>ów (odsłona druga)


Operator przypisania<br />

2<br />

class LZespolona { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

public :<br />

float re, im;<br />

}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

int main( )<br />

{<br />

LZespolona Z1, Z2, Z3, Z4;<br />

}<br />

Z1 ❤ ✭✭✭✭✭✭ ❤❤❤❤❤ = 0;<br />

Z1 = Z2 = Z3 = Z4;<br />

Operacja przypisania domyślnie realizowana jest tylko między obiektami tego samego typu. Jej<br />

istotna˛<br />

cecha˛<br />

jest to, że może ona być realizowana w sposób kaskadowy (kilka przypisań złożonych<br />

w jedna˛<br />

instrukcję).<br />

Przeciażanie ˛ <strong>operator</strong>ów (odsłona druga)


Operator przypisania<br />

3<br />

class LZespolona { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

public :<br />

float re, im;<br />

LZespolona & <strong>operator</strong> = ( LZespolona Z)<br />

{ re = Z. re; im = Z. im; return ∗this ; }<br />

}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

int main( )<br />

{<br />

LZespolona Z1, Z2, Z3, Z4;<br />

}<br />

Z1 = Z2 = Z3 = Z4;<br />

Przeciażanie ˛ <strong>operator</strong>ów (odsłona druga)


Operator przypisania<br />

3<br />

class LZespolona { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

public :<br />

float re, im;<br />

LZespolona & <strong>operator</strong> = ( LZespolona Z)<br />

{ re = Z. re; im = Z. im; return ∗this ; }<br />

}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

int main( )<br />

{<br />

LZespolona Z1, Z2, Z3, Z4;<br />

}<br />

Z1 = Z2 = Z3 = Z4;<br />

Domyślna implementacja operacji przypisania jest znacznie bardziej efektywna niż zwykłe przepisywanie<br />

wartości poszczególnych pól. Dlatego też jeżeli nie jest to konieczne, to nie należy reimplementować<br />

tej operacji.<br />

Przeciażanie ˛ <strong>operator</strong>ów (odsłona druga)


Operator przypisania<br />

4<br />

Z1 = Z2 = Z3 = Z4;<br />

Przeciażanie ˛ <strong>operator</strong>ów (odsłona druga)


Operator przypisania<br />

4<br />

Z1 = Z2 = Z3 = Z4;<br />

Operacja przypisania jest prawostronnie łaczna<br />

˛<br />

Z1 = (Z2 = (Z3 = Z4));<br />

Przeciażanie ˛ <strong>operator</strong>ów (odsłona druga)


Operator przypisania<br />

4<br />

Z1 = Z2 = Z3 = Z4;<br />

Operacja przypisania jest prawostronnie łaczna<br />

˛<br />

Z1 = (Z2 = (Z3 = Z4));<br />

⇓<br />

Z1 = Z2 = Z3 = Z4;<br />

// Wykonane zostaje działanie przypisania.<br />

Przeciażanie ˛ <strong>operator</strong>ów (odsłona druga)


Operator przypisania<br />

4<br />

Z1 = Z2 = Z3 = Z4;<br />

Operacja przypisania jest prawostronnie łaczna<br />

˛<br />

Z1 = (Z2 = (Z3 = Z4));<br />

⇓<br />

Z1 = Z2 = Z3 = Z4;<br />

⇓<br />

Z1 = Z2 = Z3;<br />

// Wykonane zostaje działanie przypisania.<br />

// Po wykonaniu przypisania zwracana jest referencja<br />

// do obiektu po lewej stronie.<br />

Przeciażanie ˛ <strong>operator</strong>ów (odsłona druga)


Operator przypisania<br />

4<br />

Z1 = Z2 = Z3 = Z4;<br />

Operacja przypisania jest prawostronnie łaczna<br />

˛<br />

Z1 = (Z2 = (Z3 = Z4));<br />

⇓<br />

Z1 = Z2 = Z3 = Z4;<br />

⇓<br />

Z1 = Z2 = Z3;<br />

// Wykonane zostaje działanie przypisania.<br />

// Po wykonaniu przypisania zwracana jest referencja<br />

// do obiektu po lewej stronie.<br />

⇓ // itd. . . .<br />

Z1 = Z2 = Z3;<br />

Przeciażanie ˛ <strong>operator</strong>ów (odsłona druga)


Operator przypisania<br />

4<br />

Z1 = Z2 = Z3 = Z4;<br />

Operacja przypisania jest prawostronnie łaczna<br />

˛<br />

Z1 = (Z2 = (Z3 = Z4));<br />

⇓<br />

Z1 = Z2 = Z3 = Z4;<br />

⇓<br />

Z1 = Z2 = Z3;<br />

// Wykonane zostaje działanie przypisania.<br />

// Po wykonaniu przypisania zwracana jest referencja<br />

// do obiektu po lewej stronie.<br />

⇓ // itd. . . .<br />

Z1 = Z2 = Z3;<br />

⇓<br />

Z1 = Z2;<br />

Przeciażanie ˛ <strong>operator</strong>ów (odsłona druga)


Operator przypisania<br />

4<br />

Z1 = Z2 = Z3 = Z4;<br />

Operacja przypisania jest prawostronnie łaczna<br />

˛<br />

Z1 = (Z2 = (Z3 = Z4));<br />

⇓<br />

Z1 = Z2 = Z3 = Z4;<br />

⇓<br />

Z1 = Z2 = Z3;<br />

// Wykonane zostaje działanie przypisania.<br />

// Po wykonaniu przypisania zwracana jest referencja<br />

// do obiektu po lewej stronie.<br />

⇓ // itd. . . .<br />

Z1 = Z2 = Z3;<br />

⇓<br />

Z1 = Z2;<br />

⇓<br />

Z1 = Z2;<br />

Przeciażanie ˛ <strong>operator</strong>ów (odsłona druga)


Operator przypisania<br />

5<br />

class LZespolona { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

public :<br />

float re, im;<br />

void <strong>operator</strong> = ( LZespolona Z)<br />

{ re = Z. re; im = Z. im; }<br />

}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

int main( )<br />

{<br />

LZespolona Z1, Z2, Z3, Z4;<br />

}<br />

Z1 ❤ ✭✭✭✭✭✭ ❤❤❤❤❤ = Z2 ❤ ✭✭✭✭✭✭ ❤❤❤❤❤<br />

= Z3 = Z4;<br />

Przeciażanie ˛ <strong>operator</strong>ów (odsłona druga)


Operator przypisania<br />

5<br />

class LZespolona { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

public :<br />

float re, im;<br />

void <strong>operator</strong> = ( LZespolona Z)<br />

{ re = Z. re; im = Z. im; }<br />

}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

int main( )<br />

{<br />

LZespolona Z1, Z2, Z3, Z4;<br />

}<br />

Z1 ❤ ✭✭✭✭✭✭ ❤❤❤❤❤ = Z2 ❤ ✭✭✭✭✭✭ ❤❤❤❤❤<br />

= Z3 = Z4;<br />

Zaniechanie zwracania referencji lub zwrócenie referencji stałej w definicji przeciażenia ˛ <strong>operator</strong>a<br />

przypisania uniemożliwia kaskadowa˛<br />

realizację tej operacji.<br />

Przeciażanie ˛ <strong>operator</strong>ów (odsłona druga)


Operator przypisania<br />

6<br />

class LZespolona { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

public :<br />

float re, im;<br />

LZespolona & <strong>operator</strong> = (float Arg)<br />

{ re = im = Arg; return ∗this ; }<br />

}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

int main( )<br />

{<br />

LZespolona Z1, Z2, Z3, Z4;<br />

}<br />

Z1 = 0;<br />

Z1 = Z2 = Z3 = Z4 = 0;<br />

Przeciażanie ˛ <strong>operator</strong>ów (odsłona druga)


Operator przypisania<br />

6<br />

class LZespolona { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

public :<br />

float re, im;<br />

LZespolona & <strong>operator</strong> = (float Arg)<br />

{ re = im = Arg; return ∗this ; }<br />

}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

int main( )<br />

{<br />

LZespolona Z1, Z2, Z3, Z4;<br />

}<br />

Z1 = 0;<br />

Z1 = Z2 = Z3 = Z4 = 0;<br />

Przeciażenie ˛ <strong>operator</strong>a przypisania dla argumentu odmiennego typu niż klasa, w której to przeciażenie<br />

˛ jest definiowane, nie wyklucza możliwości korzystania z domyślnej implementacji operacji<br />

przypisania.<br />

Przeciażanie ˛ <strong>operator</strong>ów (odsłona druga)


Operator dodania i przypisania<br />

7<br />

class LZespolona { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

public :<br />

float re, im;<br />

LZespolona & <strong>operator</strong> += ( const LZespolona& Z)<br />

{ re += Z. re; im += Z. im; return ∗this ; }<br />

}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

int main( )<br />

{<br />

LZespolona Z1, Z2, Z3, Z4;<br />

}<br />

Z1 += Z2 += Z3 += Z4;<br />

Przeciażanie ˛ <strong>operator</strong>ów (odsłona druga)


Operator dodania i przypisania<br />

7<br />

class LZespolona { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

public :<br />

float re, im;<br />

LZespolona & <strong>operator</strong> += ( const LZespolona& Z)<br />

{ re += Z. re; im += Z. im; return ∗this ; }<br />

}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

int main( )<br />

{<br />

LZespolona Z1, Z2, Z3, Z4;<br />

}<br />

Z1 += Z2 += Z3 += Z4;<br />

Operator dodania i przypisania jest również <strong>operator</strong>em prawostronnie łacznym. ˛ Przekazanie argumentu<br />

operacji przez referencję zapobiega tworzeniu kopii tego obiektu. Stałość referencji pozwala<br />

użyć jako drugiego argumentu operacji zarówno obiektów stałych, jak też modyfikowalnych.<br />

Przeciażanie ˛ <strong>operator</strong>ów (odsłona druga)


8<br />

Operator dodania i przypisania – warianty implementacji przeciażeń<br />

˛<br />

class LZespolona { //. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

public :<br />

float re, im;<br />

LZespolona & <strong>operator</strong> += ( const LZespolona & Z )<br />

{ re += Z. re; im += Z. im; return ∗this ; }<br />

LZespolona <strong>operator</strong> + ( LZespolona Z2 ) const { return Z2 += ∗this ; }<br />

}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

int main( )<br />

{<br />

LZespolona Z1, Z2, Z3;<br />

}<br />

Z1 = Z2 + Z3;<br />

Przeciażanie ˛ <strong>operator</strong>ów (odsłona druga)


8<br />

Operator dodania i przypisania – warianty implementacji przeciażeń<br />

˛<br />

class LZespolona { //. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

public :<br />

float re, im;<br />

LZespolona & <strong>operator</strong> += ( const LZespolona & Z )<br />

{ re += Z. re; im += Z. im; return ∗this ; }<br />

LZespolona <strong>operator</strong> + ( LZespolona Z2 ) const { return Z2 += ∗this ; }<br />

}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

int main( )<br />

{<br />

LZespolona Z1, Z2, Z3;<br />

}<br />

Z1 = Z2 + Z3;<br />

Przeciażaj ˛ ac ˛ wcześniej <strong>operator</strong> dodania i przypisania można w prosty i efektywny sposób zapisać<br />

definicję <strong>operator</strong>a dodawania. Operator ten powinien zwracać wartość, a nie referencję.<br />

Przeciażanie ˛ <strong>operator</strong>ów (odsłona druga)


9<br />

Operator odejmowania i przypisania – warianty implementacji przeciażeń<br />

˛<br />

class LZespolona { //. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

public :<br />

float re, im;<br />

LZespolona & <strong>operator</strong> –= ( const LZespolona & Z )<br />

{ re –= Z. re; im –= Z. im; return ∗this ; }<br />

LZespolona <strong>operator</strong> – ( const LZespolona & Z2 ) const<br />

{ return LZespolona(∗this ) –= Z2; }<br />

}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

int main( )<br />

{<br />

LZespolona Z1, Z2, Z3;<br />

}<br />

Z1 = Z2 – Z3;<br />

Przeciażanie ˛ <strong>operator</strong>ów (odsłona druga)


9<br />

Operator odejmowania i przypisania – warianty implementacji przeciażeń<br />

˛<br />

class LZespolona { //. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

public :<br />

float re, im;<br />

LZespolona & <strong>operator</strong> –= ( const LZespolona & Z )<br />

{ re –= Z. re; im –= Z. im; return ∗this ; }<br />

LZespolona <strong>operator</strong> – ( const LZespolona & Z2 ) const<br />

{ return LZespolona(∗this ) –= Z2; }<br />

}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

int main( )<br />

{<br />

LZespolona Z1, Z2, Z3;<br />

}<br />

Z1 = Z2 – Z3;<br />

W przypadku operacji nieprzemiennych należy zastosować bardziej ogólny schemat definiowania<br />

przeciażenia ˛ <strong>operator</strong>a, tak jak to ma miejsce dla operacji odejmowania.<br />

Przeciażanie ˛ <strong>operator</strong>ów (odsłona druga)


10<br />

Operator mnożenia – warianty implementacji przeciażeń<br />

˛<br />

class LZespolona { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

public :<br />

float re, im;<br />

LZespolona(float r, float i) { re = r; im = i; }<br />

LZespolona <strong>operator</strong> ∗ (const LZespolona & Z2) const;<br />

}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

LZespolona LZespolona::<strong>operator</strong> ∗ (const LZespolona & Z2) const<br />

{<br />

return LZespolona( re∗Z2. re – im∗Z2. im, re∗Z2. im + im∗Z2. re );<br />

}<br />

int main( )<br />

{<br />

LZespolona<br />

Z1(0,0), Z2(2,1), Z3(9,3);<br />

}<br />

Z1 = Z2 ∗ Z3;<br />

Przeciażanie ˛ <strong>operator</strong>ów (odsłona druga)


10<br />

Operator mnożenia – warianty implementacji przeciażeń<br />

˛<br />

class LZespolona { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

public :<br />

float re, im;<br />

LZespolona(float r, float i) { re = r; im = i; }<br />

LZespolona <strong>operator</strong> ∗ (const LZespolona & Z2) const;<br />

}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

LZespolona LZespolona::<strong>operator</strong> ∗ (const LZespolona & Z2) const<br />

{<br />

return LZespolona( re∗Z2. re – im∗Z2. im, re∗Z2. im + im∗Z2. re );<br />

}<br />

int main( )<br />

{<br />

LZespolona<br />

Z1(0,0), Z2(2,1), Z3(9,3);<br />

}<br />

Z1 = Z2 ∗ Z3;<br />

Wykorzystanie konstruktora może ułatwić zapis procedury tworzenia końcowego wyniku, gdyż ła-<br />

˛<br />

czymy w ten sposób konstrukcję obiektu i jego inicjalizację. W takim przypadku drugi argument<br />

powinien być przekazany przez stała˛<br />

referencję, aby uniknać ˛ zbędnego kopiowania.<br />

Przeciażanie ˛ <strong>operator</strong>ów (odsłona druga)


Przed- i przyrostkowe <strong>operator</strong>y inkrementacji<br />

11<br />

class LZespolona { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

public :<br />

float re, im;<br />

LZespolona & <strong>operator</strong> ++ ( ) { ++ re; ++ im; return ∗this ; } // ++Z<br />

LZespolona <strong>operator</strong> ++ ( int )<br />

{ LZespolona Z(∗this ); ++∗this ; return Z; } // Z++<br />

}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

int main( )<br />

{<br />

LZespolona Z1;<br />

}<br />

Z1. re = Z1. im = 2;<br />

Z1++. re<br />

❤❤❤❤❤❤<br />

✭✭✭✭✭✭<br />

+= 1;<br />

Przeciażanie ˛ <strong>operator</strong>ów (odsłona druga)


Przed- i przyrostkowe <strong>operator</strong>y inkrementacji<br />

11<br />

class LZespolona { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

public :<br />

float re, im;<br />

LZespolona & <strong>operator</strong> ++ ( ) { ++ re; ++ im; return ∗this ; } // ++Z<br />

LZespolona <strong>operator</strong> ++ ( int )<br />

{ LZespolona Z(∗this ); ++∗this ; return Z; } // Z++<br />

}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

int main( )<br />

{<br />

LZespolona Z1;<br />

}<br />

Z1. re = Z1. im = 2;<br />

Z1++. re<br />

❤❤❤❤❤❤<br />

✭✭✭✭✭✭<br />

+= 1;<br />

Rozróżnienie <strong>operator</strong>a przed- od przyrostkowego jest realizowane przez wprowadzenie parametru<br />

typu int. Wskazane jest, aby przeciażenie ˛ <strong>operator</strong>a przedrostkowego zwracało referencję do<br />

obiektu, zaś przyrostkowego kopię. Jednak nie jest to obowiazkowe.<br />

˛<br />

Przeciażanie ˛ <strong>operator</strong>ów (odsłona druga)


Operatory – i +<br />

12<br />

class LZespolona { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

public :<br />

float re, im;<br />

LZespolona & <strong>operator</strong> + ( ) const { return ∗this ; }<br />

LZespolona & <strong>operator</strong> – ( ) { re = – re; im = – im; return ∗this ; }<br />

}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

int main( )<br />

{<br />

LZespolona Z1;<br />

}<br />

Z1. re = Z1. im = 2;<br />

(–Z1). re += 1;<br />

Przeciażanie ˛ <strong>operator</strong>ów (odsłona druga)


Operatory – i +<br />

12<br />

class LZespolona { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

public :<br />

float re, im;<br />

LZespolona & <strong>operator</strong> + ( ) const { return ∗this ; }<br />

LZespolona & <strong>operator</strong> – ( ) { re = – re; im = – im; return ∗this ; }<br />

}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

int main( )<br />

{<br />

LZespolona Z1;<br />

}<br />

Z1. re = Z1. im = 2;<br />

(–Z1). re += 1;<br />

Implementacja przeciażeń ˛ <strong>operator</strong>ów powinna, o ile to jest tylko możliwe, być zgodna z intuicyjnym<br />

rozumieniem <strong>operator</strong>ów. Przeciażenia, ˛ które nie zmieniaja˛<br />

stanu obiektu, powinny być definiowane<br />

jako metody “stałe”.<br />

Przeciażanie ˛ <strong>operator</strong>ów (odsłona druga)


Problem z priorytetami<br />

13<br />

class Wektor3f { //. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

public :<br />

float x, y, z;<br />

Wektor3f <strong>operator</strong> ∗ (const Wektor3f & W2) const; // Iloczyn wektorowy<br />

float <strong>operator</strong> & (const Wektor3f & W2) const; // Iloczyn skalarny<br />

}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

. . .<br />

int main( )<br />

{<br />

Wektor2f V1, V2;<br />

}<br />

if (<br />

V1<br />

❤❤❤❤❤❤❤❤❤<br />

✭✭✭✭✭✭✭✭✭<br />

& V2 > 0 ) { . . . } // Zwyczajowy zapis: V 1 ·V 2 > 0<br />

if ( (V1 & V2) > 0 ) { . . . }<br />

Przeciażanie ˛ <strong>operator</strong>ów (odsłona druga)


Problem z priorytetami<br />

13<br />

class Wektor3f { //. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

public :<br />

float x, y, z;<br />

Wektor3f <strong>operator</strong> ∗ (const Wektor3f & W2) const; // Iloczyn wektorowy<br />

float <strong>operator</strong> & (const Wektor3f & W2) const; // Iloczyn skalarny<br />

}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

. . .<br />

int main( )<br />

{<br />

Wektor2f V1, V2;<br />

}<br />

if (<br />

V1<br />

❤❤❤❤❤❤❤❤❤<br />

✭✭✭✭✭✭✭✭✭<br />

& V2 > 0 ) { . . . } // Zwyczajowy zapis: V 1 ·V 2 > 0<br />

if ( (V1 & V2) > 0 ) { . . . }<br />

Dobór <strong>operator</strong>ów do realizacji poszczególnych operacji powinien być możliwie zbliżony do ich pierwotnego<br />

znaczenia. Jednak z drugiej strony wzajemne priorytety <strong>operator</strong>ów powinny odpowiadać<br />

priorytetom implementowanych operacji. Nie zawsze te wymagania daja˛<br />

się pogodzić.<br />

Przeciażanie ˛ <strong>operator</strong>ów (odsłona druga)


Operator indeksujacy<br />

˛<br />

class Wektor3f { //. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

public :<br />

float x, y, z;<br />

14<br />

float <strong>operator</strong> [ ] ( unsigned int ind ) const<br />

{ return ind ? ind == 1 ? y : z : x; }<br />

float & <strong>operator</strong> [ ] ( unsigned int ind )<br />

{ return ind ? ind == 1 ? y : z : x; }<br />

}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

int main( )<br />

{<br />

Wektor2f V1, V2;<br />

}<br />

V1.x = V2[2];<br />

V1[2] = V2.z;<br />

Przeciażanie ˛ <strong>operator</strong>ów (odsłona druga)


Operator indeksujacy<br />

˛<br />

class Wektor3f { //. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

public :<br />

float x, y, z;<br />

14<br />

float <strong>operator</strong> [ ] ( unsigned int ind ) const<br />

{ return ind ? ind == 1 ? y : z : x; }<br />

float & <strong>operator</strong> [ ] ( unsigned int ind )<br />

{ return ind ? ind == 1 ? y : z : x; }<br />

}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

int main( )<br />

{<br />

Wektor2f V1, V2;<br />

}<br />

V1.x = V2[2];<br />

V1[2] = V2.z;<br />

Przeciażenie ˛ <strong>operator</strong> indeksujacego ˛ pozwala na dostęp do tych samych struktur na dwa sposoby.<br />

Pierwszy z nich pozwala odwołać do konkretnych pól po nazwie, drugi zaś pozwala widzieć cała˛<br />

strukturę jako tablicę. Podwójne przeciażenie ˛ pozwala na realizację zarówno odczytu jak też zapisu.<br />

Przedstawiona implementacja przeciażeń ˛ nie zapewnia pełnej kontroli zakresu.<br />

Przeciażanie ˛ <strong>operator</strong>ów (odsłona druga)


Operator indeksujacy<br />

˛<br />

15<br />

class Wektor3f { //. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

public :<br />

union { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

float Tab[3];<br />

struct { float x, y, z; };<br />

}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

float <strong>operator</strong> [ ] ( unsigned int ind ) const { return Tab[ ind ]; }<br />

float & <strong>operator</strong> [ ] ( unsigned int ind ) { return Tab[ ind ]; }<br />

}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

int main( )<br />

{<br />

Wektor2f V1, V2;<br />

}<br />

V1.x = V2[2];<br />

V1[2] = V2.z;<br />

Przeciażanie ˛ <strong>operator</strong>ów (odsłona druga)


Operator indeksujacy<br />

˛<br />

15<br />

class Wektor3f { //. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

public :<br />

union { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

float Tab[3];<br />

struct { float x, y, z; };<br />

}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

float <strong>operator</strong> [ ] ( unsigned int ind ) const { return Tab[ ind ]; }<br />

float & <strong>operator</strong> [ ] ( unsigned int ind ) { return Tab[ ind ]; }<br />

}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

int main( )<br />

{<br />

Wektor2f V1, V2;<br />

}<br />

V1.x = V2[2];<br />

V1[2] = V2.z;<br />

Wykorzystanie w definicji nienazwanej unii zapewnia realizację znacznie bardziej efektywnego dostępu<br />

na różne sposoby do tego samego obszaru pamięci. (Niestety niedopuszczalne w ANSI C++ :(<br />

Przeciażanie ˛ <strong>operator</strong>ów (odsłona druga)


Operator indeksujacy<br />

˛<br />

16<br />

class Wektor3f { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

union { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

float Tab[3];<br />

struct { float x, y, z; };<br />

}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

public :<br />

union { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

struct { float x, y, z; };<br />

}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

float <strong>operator</strong> [ ] ( unsigned int ind ) const { return Tab[ ind ]; }<br />

float & <strong>operator</strong> [ ] ( unsigned int ind ) { return Tab[ ind ]; }<br />

float Norma( ) const { return sqrt( x∗ x + y∗ y + z∗ z); }<br />

}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

Przeciażanie ˛ <strong>operator</strong>ów (odsłona druga)


Operator indeksujacy<br />

˛<br />

16<br />

class Wektor3f { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

union { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

float Tab[3];<br />

struct { float x, y, z; };<br />

}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

public :<br />

union { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

struct { float x, y, z; };<br />

}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

float <strong>operator</strong> [ ] ( unsigned int ind ) const { return Tab[ ind ]; }<br />

float & <strong>operator</strong> [ ] ( unsigned int ind ) { return Tab[ ind ]; }<br />

float Norma( ) const { return sqrt( x∗ x + y∗ y + z∗ z); }<br />

}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

Unie nienazwane pozwalaja˛<br />

odwoływać się do tego samego obszaru pamięci nie tylko w różny sposób,<br />

ale również pozwalaja˛<br />

tworzyć konstrukcje definiujace ˛ dostępność ze względu na zadany sposób<br />

odwołania do pamięci. Nie należy jednak nadużywać tego mechanizmu do tworzenia wielu<br />

synonimów nazw pól.<br />

Przeciażanie ˛ <strong>operator</strong>ów (odsłona druga)


Operator funkcyjny<br />

17<br />

class Macierz3x3f { //. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

float Tab[3][3];<br />

public :<br />

float <strong>operator</strong> ( ) (unsigned int i, unsigned int j) const{ return Tab[ i ][ j ]; }<br />

float& <strong>operator</strong> ( ) (unsigned int i, unsigned int j) { return Tab[ i ][ j ]; }<br />

}; //. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

int main( )<br />

{<br />

Macierz3x3f M;<br />

}<br />

M(1,2) = 5;<br />

M(1,1) = M(1,2);<br />

Przeciażanie ˛ <strong>operator</strong>ów (odsłona druga)


Operator funkcyjny<br />

17<br />

class Macierz3x3f { //. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

float Tab[3][3];<br />

public :<br />

float <strong>operator</strong> ( ) (unsigned int i, unsigned int j) const{ return Tab[ i ][ j ]; }<br />

float& <strong>operator</strong> ( ) (unsigned int i, unsigned int j) { return Tab[ i ][ j ]; }<br />

}; //. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .<br />

int main( )<br />

{<br />

Macierz3x3f M;<br />

}<br />

M(1,2) = 5;<br />

M(1,1) = M(1,2);<br />

Przeciażenie ˛ <strong>operator</strong>ów wywołania funkcji pozwala na organizację wygodnego dostępu do wewnętrznych<br />

struktur tablicowych.<br />

Przeciażanie ˛ <strong>operator</strong>ów (odsłona druga)


Pytania i ćwiczenia<br />

18<br />

1. Dany jest fragment kodu:<br />

class ProstaKlasa {<br />

int Pole;<br />

public:<br />

void Zmien(int Wart) { Pole = Wart; }<br />

};<br />

int main()<br />

{<br />

ProstaKlasa const Ob;<br />

ProstaKlasa &Ref = Ob;<br />

. . .<br />

A. Czy powyżej w poprawny sposób utworzona została referencja do obiektu Ob?<br />

B. Jeżeli nie, to jak należy to zapisać aby operacja była poprawna (nie zmieniajac<br />

˛<br />

deklaracji referencji Ref)?<br />

C. Jeżeli tak, to jak należy to zapisać aby uniemożliwić taka˛<br />

operację?<br />

D. Czy po utworzeniu referencji Ref będzie się można poprzez nia˛<br />

odwołać do metody<br />

Zmien?<br />

Przeciażanie ˛ <strong>operator</strong>ów (odsłona druga)


Pytania i problemy<br />

19<br />

2. Dana jest definicja klasy LZespolona:<br />

class LZespolona {<br />

public :<br />

float re, im;<br />

LZespolona <strong>operator</strong> = ( LZespolona Z)<br />

{ re = Z. re; im = Z. im; return ∗this ; }<br />

};<br />

Niech będa˛<br />

dane zmienne: LZespolona Z1, Z2, Z3. Czy dwie poniższe operacje daja˛<br />

taki<br />

sam wynik?<br />

Z1 = Z2 = Z3;<br />

(Z1 = Z2) = Z3;<br />

Jeżeli tak, to jaki zachodzi zwiazek ˛ między wartościami zmiennych? Jeżeli natomiast nie, to<br />

co należy zrobić, aby wynik był taki sam?<br />

3. Dana jest definicja klasy:<br />

class LZespolona {<br />

public :<br />

float re, im;<br />

LZespolona & <strong>operator</strong> ++ (int) { ++ re; ++ im; return ∗this ; }<br />

};<br />

Czy działanie przedstawione poniżej jest prawidłowo zapisane (w sensie składni)?<br />

LZespolona Z1; Z. re = Z. im = 2; ++Z. re += 1;<br />

Jeżeli tak, to jaki jest wynik działania? Jeżeli nie, to co należy zrobić, aby było ono poprawne.<br />

Przeciażanie ˛ <strong>operator</strong>ów (odsłona druga)

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!