operator
operator
operator
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)