Przeci ˛
a˙zanie operatorów (odsłona druga)
Bogdan Kreczmer
ZPCiR IIAiR PWr
pokój 307 budynek C3
bogdan.kreczmer@pwr.wroc.pl
Copyright c
°
2005–2009 Bogdan Kreczmer
?
?
Niniejszy dokument zawiera materiały do wykładu na temat programowania obiektowego. Jest on udost ˛epniony pod
warunkiem wykorzystania wył ˛
acznie do własnych prywatnych potrzeb i mo˙ze on by´c kopiowany wył ˛
acznie w cało´sci, razem z
niniejsz ˛
a stron ˛
a tytułow ˛
a.
1
Operatory arytmetyczne, bitowe i logiczne
(i nie tylko)
Indeksowanie
wska´znik
[
wyra˙zenie
]
Wywołanie funkcji
wyra˙zenie
(
lista wyra˙ze ´n
)
Przyrostkowa inkrementacja
l-warto´s´c
++
Przyrostkowa dekrementacja
l-warto´s´c
- -
Przedrostkowa inkrementacja
++
l-warto´s´c
Przedrostkowa dekrementacja
- -
l-warto´s´c
Negacja bitowa
∼
wyra˙zenie
Negacja logiczna
!
wyra˙zenie
Minus jednoargumentowy
-
wyra˙zenie
Plus jednoargumentowy
+
wyra˙zenie
Mno˙zenie
wyra˙zenie
∗
wyra˙zenie
Dzielenie
wyra˙zenie
/
wyra˙zenie
Modulo
wyra˙zenie
%
wyra˙zenie
Dodawanie
wyra˙zenie
+
wyra˙zenie
Odejmowanie
wyra˙zenie
-
wyra˙zenie
Przesuwanie w lewo
wyra˙zenie
<<
wyra˙zenie
Przesuwanie w prawo
wyra˙zenie
>>
wyra˙zenie
Mniejszy
wyra˙zenie
<
wyra˙zenie
Mniejszy lub równy
wyra˙zenie
<=
wyra˙zenie
Wi ˛ekszy
wyra˙zenie
>
wyra˙zenie
Wi ˛ekszy lub równy
wyra˙zenie
>=
wyra˙zenie
⇓
⇓
Równy
wyra˙zenie
==
wyra˙zenie
Nierówny
wyra˙zenie
!=
wyra˙zenie
Koniunkcja bitowa
wyra˙zenie
&
wyra˙zenie
Ró˙znica symetryczna
wyra˙zenie
ˆ
wyra˙zenie
Alternatywa bitowa
wyra˙zenie
|
wyra˙zenie
Iloczyn logiczny
wyra˙zenie
&&
wyra˙zenie
Suma logiczna
wyra˙zenie
||
wyra˙zenie
Wyra˙zenie warunkowe
wyra˙zenie
?
wyr.
:
wyr.
Proste przypisanie
l-warto´s´c
=
wyra˙zenie
Przemnó˙z i przypisz
l-warto´s´c
∗
=
wyra˙zenie
Podziel i przypisz
l-warto´s´c
/=
wyra˙zenie
We´z modulo i przypisz
l-warto´s´c
%=
wyra˙zenie
Dodaj i przypisz
l-warto´s´c
+=
wyra˙zenie
Odejmij i przypisz
l-warto´s´c
-=
wyra˙zenie
Przesu ´n w lewo i przypisz
l-warto´s´c
<<
=
wyr.
Przesu ´n w prawo i przypisz
l-warto´s´c
>>
=
wyr.
Koniunkcja bitowa i przypisz
l-warto´s´c
&=
wyra˙zenie
Alternatywa bitowa i przypisz
l-warto´s´c
&=
wyra˙zenie
Ró˙znica bitowa i przypisz
l-warto´s´c
ˆ
=
wyra˙zenie
Operatory zawarte w tej samej cz ˛e´sci tabeli maj ˛
a ten
sam priorytet.
Przeci ˛
a˙zanie operatorów (odsłona druga)
2
Jaka wy ´swietli si ˛e warto ´s ´c
#
include
<
iostream
>
using namespace std;
int main( )
{
int
x = 1;
cout
<<
++x++
<<
endl
;
}
Przeci ˛
a˙zanie operatorów (odsłona druga)
2
Jaka wy ´swietli si ˛e warto ´s ´c
#
include
<
iostream
>
using namespace std;
int main( )
{
int
x = 1;
cout
<<
++x++
<<
endl
;
}
Nie wy´swietli ˙zadna warto´s´c, gdy˙z zapis ten jest bł ˛edny.
Przeci ˛
a˙zanie operatorów (odsłona druga)
3
Operator przypisania
class LZespolona { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
public :
float
re, im;
}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
int main( )
{
LZespolona
Z1, Z2, Z3, Z4;
Z1
hhh
hh
h
((
((
(
(
= 0
;
Z1 = Z2 = Z3 = Z4
;
}
Przeci ˛
a˙zanie operatorów (odsłona druga)
3
Operator przypisania
class LZespolona { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
public :
float
re, im;
}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
int main( )
{
LZespolona
Z1, Z2, Z3, Z4;
Z1
hhh
hh
h
((
((
(
(
= 0
;
Z1 = Z2 = Z3 = Z4
;
}
Operacja przypisania domy´slnie realizowana jest tylko mi ˛edzy obiektami tego samego typu. Jej
istotn ˛
a cech ˛
a jest to, ˙ze mo˙ze ona by´c realizowana w sposób kaskadowy (kilka przypisa ´n zło˙zonych
w jedn ˛
a instrukcj ˛e).
Przeci ˛
a˙zanie operatorów (odsłona druga)
4
Operator przypisania
class LZespolona { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
public :
float
re, im;
LZespolona & operator
=
(
LZespolona Z)
{ re = Z. re;
im = Z. im;
return
∗
this ; }
}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
int main( )
{
LZespolona
Z1, Z2, Z3, Z4;
Z1 = Z2 = Z3 = Z4
;
}
Przeci ˛
a˙zanie operatorów (odsłona druga)
4
Operator przypisania
class LZespolona { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
public :
float
re, im;
LZespolona & operator
=
(
LZespolona Z)
{ re = Z. re;
im = Z. im;
return
∗
this ; }
}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
int main( )
{
LZespolona
Z1, Z2, Z3, Z4;
Z1 = Z2 = Z3 = Z4
;
}
Domy´slna implementacja operacji przypisania jest znacznie bardziej efektywna ni˙z zwykłe przepisy-
wanie warto´sci poszczególnych pól. Dlatego te˙z je˙zeli nie jest to konieczne, to nie nale˙zy reimple-
mentowa´c tej operacji.
Przeci ˛
a˙zanie operatorów (odsłona druga)
5
Operator przypisania
Z1 = Z2 = Z3 = Z4;
Przeci ˛
a˙zanie operatorów (odsłona druga)
5
Operator przypisania
Z1 = Z2 = Z3 = Z4;
Operacja przypisania jest prawostronnie ł ˛
aczna
Z1 = (Z2 = (Z3 = Z4));
Przeci ˛
a˙zanie operatorów (odsłona druga)
5
Operator przypisania
Z1 = Z2 = Z3 = Z4;
Operacja przypisania jest prawostronnie ł ˛
aczna
Z1 = (Z2 = (Z3 = Z4));
⇓
Z1 = Z2 =
Z3 = Z4;
//
Wykonane zostaje działanie przypisania.
Przeci ˛
a˙zanie operatorów (odsłona druga)
5
Operator przypisania
Z1 = Z2 = Z3 = Z4;
Operacja przypisania jest prawostronnie ł ˛
aczna
Z1 = (Z2 = (Z3 = Z4));
⇓
Z1 = Z2 =
Z3 = Z4;
//
Wykonane zostaje działanie przypisania.
⇓
//
Po wykonaniu przypisania zwracana jest referencja
Z1 = Z2 =
Z3;
//
do obiektu po lewej stronie.
Przeci ˛
a˙zanie operatorów (odsłona druga)
5
Operator przypisania
Z1 = Z2 = Z3 = Z4;
Operacja przypisania jest prawostronnie ł ˛
aczna
Z1 = (Z2 = (Z3 = Z4));
⇓
Z1 = Z2 =
Z3 = Z4;
//
Wykonane zostaje działanie przypisania.
⇓
//
Po wykonaniu przypisania zwracana jest referencja
Z1 = Z2 =
Z3;
//
do obiektu po lewej stronie.
⇓
//
itd. . . .
Z1 =
Z2 = Z3;
Przeci ˛
a˙zanie operatorów (odsłona druga)
5
Operator przypisania
Z1 = Z2 = Z3 = Z4;
Operacja przypisania jest prawostronnie ł ˛
aczna
Z1 = (Z2 = (Z3 = Z4));
⇓
Z1 = Z2 =
Z3 = Z4;
//
Wykonane zostaje działanie przypisania.
⇓
//
Po wykonaniu przypisania zwracana jest referencja
Z1 = Z2 =
Z3;
//
do obiektu po lewej stronie.
⇓
//
itd. . . .
Z1 =
Z2 = Z3;
⇓
Z1 =
Z2;
Przeci ˛
a˙zanie operatorów (odsłona druga)
5
Operator przypisania
Z1 = Z2 = Z3 = Z4;
Operacja przypisania jest prawostronnie ł ˛
aczna
Z1 = (Z2 = (Z3 = Z4));
⇓
Z1 = Z2 =
Z3 = Z4;
//
Wykonane zostaje działanie przypisania.
⇓
//
Po wykonaniu przypisania zwracana jest referencja
Z1 = Z2 =
Z3;
//
do obiektu po lewej stronie.
⇓
//
itd. . . .
Z1 =
Z2 = Z3;
⇓
Z1 =
Z2;
⇓
Z1 = Z2;
Przeci ˛
a˙zanie operatorów (odsłona druga)
6
Operator przypisania
class LZespolona { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
public :
float
re, im;
void operator
=
(
LZespolona Z)
{ re = Z. re;
im = Z. im; }
}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
int main( )
{
LZespolona
Z1, Z2, Z3, Z4;
Z1
hhh
hh
h
((
((
(
(
= Z2
hhh
hh
h
((
((
(
(
= Z3 = Z4
;
}
Przeci ˛
a˙zanie operatorów (odsłona druga)
6
Operator przypisania
class LZespolona { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
public :
float
re, im;
void operator
=
(
LZespolona Z)
{ re = Z. re;
im = Z. im; }
}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
int main( )
{
LZespolona
Z1, Z2, Z3, Z4;
Z1
hhh
hh
h
((
((
(
(
= Z2
hhh
hh
h
((
((
(
(
= Z3 = Z4
;
}
Zaniechanie zwracania referencji lub zwrócenie referencji stałej w definicji przeci ˛
a˙zenia operatora
przypisania uniemo˙zliwia kaskadow ˛
a realizacj ˛e tej operacji.
Przeci ˛
a˙zanie operatorów (odsłona druga)
7
Operator przypisania
class LZespolona { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
public :
float
re, im;
LZespolona & operator
=
(
float Arg)
{ re = Arg;
im = 0;
return
∗
this ; }
}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
int main( )
{
LZespolona
Z1, Z2, Z3, Z4;
Z1 = 0
;
Z1 = Z2 = Z3 = Z4 = 0
;
}
Przeci ˛
a˙zanie operatorów (odsłona druga)
7
Operator przypisania
class LZespolona { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
public :
float
re, im;
LZespolona & operator
=
(
float Arg)
{ re = Arg;
im = 0;
return
∗
this ; }
}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
int main( )
{
LZespolona
Z1, Z2, Z3, Z4;
Z1 = 0
;
Z1 = Z2 = Z3 = Z4 = 0
;
}
Przeci ˛
a˙zenie operatora przypisania dla argumentu odmiennego typu ni˙z klasa, w której to prze-
ci ˛
a˙zenie jest definiowane, nie wyklucza mo˙zliwo´sci korzystania z domy´slnej implementacji operacji
przypisania.
Przeci ˛
a˙zanie operatorów (odsłona druga)
8
Operator dodania i przypisania
class LZespolona { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
public :
float
re, im;
LZespolona & operator
+=
(
const LZespolona& Z)
{ re += Z. re;
im += Z. im;
return
∗
this ; }
}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
int main( )
{
LZespolona
Z1, Z2, Z3, Z4;
Z1 += Z2 += Z3 += Z4
;
}
Przeci ˛
a˙zanie operatorów (odsłona druga)
8
Operator dodania i przypisania
class LZespolona { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
public :
float
re, im;
LZespolona & operator
+=
(
const LZespolona& Z)
{ re += Z. re;
im += Z. im;
return
∗
this ; }
}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
int main( )
{
LZespolona
Z1, Z2, Z3, Z4;
Z1 += Z2 += Z3 += Z4
;
}
Operator dodania i przypisania jest równie˙z operatorem prawostronnie ł ˛
acznym. Przekazanie argu-
mentu operacji przez referencj ˛e zapobiega tworzeniu kopii tego obiektu. Stało´s´c referencji pozwala
u˙zy´c jako drugiego argumentu operacji zarówno obiektów stałych, jak te˙z modyfikowalnych.
Przeci ˛
a˙zanie operatorów (odsłona druga)
9
Operator dodania i przypisania
– warianty implementacji przeci ˛
a˙ze ´
n
class LZespolona { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
public :
float
re, im;
LZespolona & operator
+=
(
const LZespolona & Z )
{ re += Z. re;
im += Z. im;
return
∗
this ; }
LZespolona operator
+
(
LZespolona Z2 ) const { return Z2 +=
∗
this ; }
}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
int main( )
{
LZespolona
Z w, Z a, Z b;
Z w = Z a + Z b
;
}
Przeci ˛
a˙zanie operatorów (odsłona druga)
9
Operator dodania i przypisania
– warianty implementacji przeci ˛
a˙ze ´
n
class LZespolona { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
public :
float
re, im;
LZespolona & operator
+=
(
const LZespolona & Z )
{ re += Z. re;
im += Z. im;
return
∗
this ; }
LZespolona operator
+
(
LZespolona Z2 ) const { return Z2 +=
∗
this ; }
}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
int main( )
{
LZespolona
Z w, Z a, Z b;
Z w = Z a + Z b
;
}
Przeci ˛
a˙zaj ˛
ac wcze´sniej operator dodania i przypisania mo˙zna w prosty i efektywny sposób zapisa´c
definicj ˛e operatora dodawania. Operator ten powinien zwraca´c warto´s´c, a nie referencj ˛e.
Przeci ˛
a˙zanie operatorów (odsłona druga)
10
Operator odejmowania i przypisania
– warianty implementacji przeci ˛
a˙ze ´
n
class LZespolona { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
public :
float
re, im;
LZespolona & operator
–=
(
const LZespolona & Z )
{ re –= Z. re;
im –= Z. im;
return
∗
this ; }
LZespolona operator
–
(
const LZespolona & Z2 ) const
{
return LZespolona(
∗
this ) –= Z2; }
}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
int main( )
{
LZespolona
Z w, Z a, Z b;
Z w = Z a – Z b
;
}
Przeci ˛
a˙zanie operatorów (odsłona druga)
10
Operator odejmowania i przypisania
– warianty implementacji przeci ˛
a˙ze ´
n
class LZespolona { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
public :
float
re, im;
LZespolona & operator
–=
(
const LZespolona & Z )
{ re –= Z. re;
im –= Z. im;
return
∗
this ; }
LZespolona operator
–
(
const LZespolona & Z2 ) const
{
return LZespolona(
∗
this ) –= Z2; }
}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
int main( )
{
LZespolona
Z w, Z a, Z b;
Z w = Z a – Z b
;
}
W przypadku operacji nieprzemiennych nale˙zy zastosowa´c bardziej ogólny schemat definiowania
przeci ˛
a˙zenia operatora, tak jak to ma miejsce dla operacji odejmowania.
Przeci ˛
a˙zanie operatorów (odsłona druga)
11
Operator mno˙zenia
– warianty implementacji przeci ˛
a˙ze ´
n
class LZespolona { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
public :
float
re, im;
LZespolona(float r, float i) { re = r; im = i; }
LZespolona operator
∗
(
const LZespolona & Z2)
const;
}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
LZespolona LZespolona::operator
∗
(
const LZespolona & Z2) const
{
return
LZespolona( re
∗
Z2. re – im
∗
Z2. im,
re
∗
Z2. im + im
∗
Z2. re )
;
}
int main( )
{
LZespolona
Z w(0,0), Z a(2,1), Z b(9,3);
Z w = Z a
∗
Z b
;
}
Przeci ˛
a˙zanie operatorów (odsłona druga)
11
Operator mno˙zenia
– warianty implementacji przeci ˛
a˙ze ´
n
class LZespolona { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
public :
float
re, im;
LZespolona(float r, float i) { re = r; im = i; }
LZespolona operator
∗
(
const LZespolona & Z2)
const;
}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
LZespolona LZespolona::operator
∗
(
const LZespolona & Z2) const
{
return
LZespolona( re
∗
Z2. re – im
∗
Z2. im,
re
∗
Z2. im + im
∗
Z2. re )
;
}
int main( )
{
LZespolona
Z w(0,0), Z a(2,1), Z b(9,3);
Z w = Z a
∗
Z b
;
}
Wykorzystanie konstruktora mo˙ze ułatwi´c zapis procedury tworzenia ko ´ncowego wyniku, gdy˙z ł ˛
a-
czymy w ten sposób konstrukcj ˛e obiektu i jego inicjalizacj ˛e. W takim przypadku drugi argument
powinien by´c przekazany przez stał ˛
a referencj ˛e, aby unikn ˛
a´c zb ˛ednego kopiowania.
Przeci ˛
a˙zanie operatorów (odsłona druga)
12
Przed- i przyrostkowe operatory inkrementacji
class LZespolona { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
public :
float
re, im;
LZespolona & operator
++
( ) { ++ re; ++ im;
return
∗
this ; }
//
++Z
LZespolona
operator
++
(
int )
{
LZespolona Z(
∗
this ); ++
∗
this ; return Z; }
//
Z++
}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
int main( )
{
LZespolona
Z1;
Z1. re = Z1. im = 2;
Z1++. re += 1
;
Przeci ˛
a˙zanie operatorów (odsłona druga)
12
Przed- i przyrostkowe operatory inkrementacji
class LZespolona { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
public :
float
re, im;
LZespolona & operator
++
( ) { ++ re; ++ im;
return
∗
this ; }
//
++Z
LZespolona
operator
++
(
int )
{
LZespolona Z(
∗
this ); ++
∗
this ; return Z; }
//
Z++
}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
int main( )
{
LZespolona
Z1;
Z1. re = Z1. im = 2;
Z1++. re += 1
;
hhh
hh
h
((
((
(
(
}
Rozró˙znienie operatora przed- od przyrostkowego jest realizowane przez wprowadzenie parame-
tru typu
int. Wskazane jest, aby przeci ˛
a˙zenie operatora przedrostkowego zwracało referencj ˛e do
obiektu, za´s przyrostkowego kopi ˛e. Jednak nie jest to obowi ˛
azkowe.
Przeci ˛
a˙zanie operatorów (odsłona druga)
13
Operatory – i +
class LZespolona { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
public :
float
re, im;
LZespolona( float r = 0, float i = 0 ): re(r), im(i) { }
LZespolona operator
+
( )
const { return
∗
this ; }
LZespolona operator
–
( )
const { return LZespolona(– re,– im); }
}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
int main( )
{
LZespolona
Z1;
Z1. re = Z1. im = 2;
(–Z1). re += 1;
Przeci ˛
a˙zanie operatorów (odsłona druga)
13
Operatory – i +
class LZespolona { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
public :
float
re, im;
LZespolona( float r = 0, float i = 0 ): re(r), im(i) { }
LZespolona operator
+
( )
const { return
∗
this ; }
LZespolona operator
–
( )
const { return LZespolona(– re,– im); }
}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
int main( )
{
LZespolona
Z1;
Z1. re = Z1. im = 2;
(–Z1). re += 1;
hhh
hh
h
((
((
(
(
}
Implementacja przeci ˛
a˙ze ´n operatorów powinna, o ile to jest tylko mo˙zliwe, by´c zgodna z intuicyjnym
rozumieniem operatorów. Przeci ˛
a˙zenia, które nie zmieniaj ˛
a stanu obiektu, powinny by´c definiowane
jako metody “stałe”.
Przeci ˛
a˙zanie operatorów (odsłona druga)
14
Operatory – i +
class LZespolona { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
public :
float
re, im;
LZespolona( float r = 0, float i = 0 ): re(r), im(i) { }
const LZespolona & operator
+
( )
const { return
∗
this ; }
LZespolona operator
–
( )
const { return LZespolona(– re,– im); }
}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
int main( )
{
LZespolona
Z1;
Z1. re = Z1. im = 2;
(–Z1). re += 1;
hhh
hh
h
((
((
(
(
}
Implementacja przeci ˛
a˙ze ´n operatorów powinna, o ile to jest tylko mo˙zliwe, by´c zgodna z intuicyjnym
rozumieniem operatorów. Przeci ˛
a˙zenia, które nie zmieniaj ˛
a stanu obiektu, powinny by´c definiowane
jako metody “stałe”.
Przeci ˛
a˙zanie operatorów (odsłona druga)
15
Problem z priorytetami
class Wektor3f { //. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
public :
float
x, y, z;
Wektor3f operator
∗
(
const Wektor3f & W2) const; // Iloczyn wektorowy
float operator
&
(
const Wektor3f & W2) const
;
// Iloczyn skalarny
}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . .
int main( )
{
Wektor2f
V1, V2;
if (
hhh
hhh
hhh
((
((
((
((
(
V1 & V2
>
0
) {
. . . }
//
Zwyczajowy zapis:
V
1
·V
2
> 0
if (
(V1 & V2)
>
0
) {
. . . }
}
Przeci ˛
a˙zanie operatorów (odsłona druga)
15
Problem z priorytetami
class Wektor3f { //. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
public :
float
x, y, z;
Wektor3f operator
∗
(
const Wektor3f & W2) const; // Iloczyn wektorowy
float operator
&
(
const Wektor3f & W2) const
;
// Iloczyn skalarny
}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . .
int main( )
{
Wektor2f
V1, V2;
if (
hhh
hhh
hhh
((
((
((
((
(
V1 & V2
>
0
) {
. . . }
//
Zwyczajowy zapis:
V
1
·V
2
> 0
if (
(V1 & V2)
>
0
) {
. . . }
}
Dobór operatorów do realizacji poszczególnych operacji powinien by´c mo˙zliwie zbli˙zony do ich pier-
wotnego znaczenia. Jednak z drugiej strony wzajemne priorytety operatorów powinny odpowiada´c
priorytetom implementowanych operacji. Nie zawsze te wymagania daj ˛
a si ˛e pogodzi´c.
Przeci ˛
a˙zanie operatorów (odsłona druga)
16
Operator indeksuj ˛
acy
class Wektor3f { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
public :
float x, y, z;
float operator [ ] ( unsigned int ind ) const
{
return ind ? ind == 1 ? y : z : x; }
float & operator [ ] ( unsigned int ind )
{
return ind ? ind == 1 ? y : z : x; }
}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
int main( )
{
Wektor2f
V1, V2;
V1.x = V2[2]
;
V1[2] = V2.z
;
}
Przeci ˛
a˙zanie operatorów (odsłona druga)
16
Operator indeksuj ˛
acy
class Wektor3f { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
public :
float x, y, z;
float operator [ ] ( unsigned int ind ) const
{
return ind ? ind == 1 ? y : z : x; }
float & operator [ ] ( unsigned int ind )
{
return ind ? ind == 1 ? y : z : x; }
}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
int main( )
{
Wektor2f
V1, V2;
V1.x = V2[2]
;
V1[2] = V2.z
;
}
Przeci ˛
a˙zenie operator indeksuj ˛
acego pozwala na dost ˛ep do tych samych struktur na dwa sposoby.
Pierwszy z nich pozwala odwoła´c do konkretnych pól po nazwie, drugi za´s pozwala widzie´c cał ˛
a
struktur ˛e jako tablic ˛e. Podwójne przeci ˛
a˙zenie pozwala na realizacj ˛e zarówno odczytu jak te˙z zapisu.
Przedstawiona implementacja przeci ˛
a˙ze ´n nie zapewnia pełnej kontroli zakresu.
Przeci ˛
a˙zanie operatorów (odsłona druga)
17
Operator indeksuj ˛
acy
class Wektor3f { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
public :
union {
//
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
float
Tab[3];
struct { float x, y, z; };
}
;
//
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
float operator [ ] ( unsigned int ind ) const { return
Tab[ ind ]; }
float & operator [ ] ( unsigned int ind ) { return
Tab[ ind ]; }
}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
int main( )
{
Wektor2f
V1, V2;
V1.x = V2[2]
;
V1[2] = V2.z
;
}
Przeci ˛
a˙zanie operatorów (odsłona druga)
17
Operator indeksuj ˛
acy
class Wektor3f { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
public :
union {
//
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
float
Tab[3];
struct { float x, y, z; };
}
;
//
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
float operator [ ] ( unsigned int ind ) const { return
Tab[ ind ]; }
float & operator [ ] ( unsigned int ind ) { return
Tab[ ind ]; }
}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
int main( )
{
Wektor2f
V1, V2;
V1.x = V2[2]
;
V1[2] = V2.z
;
}
Wykorzystanie w definicji nienazwanej unii zapewnia realizacj ˛e znacznie bardziej efektywnego do-
st ˛epu na ró˙zne sposoby do tego samego obszaru pami ˛eci.
(Niestety niedopuszczalne w ANSI C++ :(
Przeci ˛
a˙zanie operatorów (odsłona druga)
18
Operator indeksuj ˛
acy
class Wektor3f { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
union {
//
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
float
Tab[3];
struct { float
x, y, z; };
}
;
//
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
public :
union {
//
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
struct { float x, y, z; };
}
;
//
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
float operator [ ] ( unsigned int ind ) const { return
Tab[ ind ]; }
float & operator [ ] ( unsigned int ind ) { return
Tab[ ind ]; }
float Norma( ) const { return sqrt( x
∗
x + y
∗
y + z
∗
z); }
}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Przeci ˛
a˙zanie operatorów (odsłona druga)
18
Operator indeksuj ˛
acy
class Wektor3f { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
union {
//
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
float
Tab[3];
struct { float
x, y, z; };
}
;
//
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
public :
union {
//
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
struct { float x, y, z; };
}
;
//
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
float operator [ ] ( unsigned int ind ) const { return
Tab[ ind ]; }
float & operator [ ] ( unsigned int ind ) { return
Tab[ ind ]; }
float Norma( ) const { return sqrt( x
∗
x + y
∗
y + z
∗
z); }
}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Unie nienazwane pozwalaj ˛
a odwoływa´c si ˛e do tego samego obszaru pami ˛eci nie tylko w ró˙zny spo-
sób, ale równie˙z pozwalaj ˛
a tworzy´c konstrukcje definiuj ˛
ace dost ˛epno´s´c ze wzgl ˛edu na zadany spo-
sób odwołania do pami ˛eci. Nie nale˙zy jednak nadu˙zywa´c tego mechanizmu do tworzenia wielu
synonimów nazw pól.
Przeci ˛
a˙zanie operatorów (odsłona druga)
19
Operator funkcyjny
class Macierz3x3f { //. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
float
Tab[3][3];
public :
float operator ( ) (unsigned int i, unsigned int j) const { return
Tab[ i ][ j ]; }
float& operator ( ) (unsigned int i, unsigned int j) { return
Tab[ i ][ j ]; }
}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
int main( )
{
Macierz3x3f M;
M(1,2) = 5
;
M(1,1) = M(1,2)
;
}
Przeci ˛
a˙zanie operatorów (odsłona druga)
19
Operator funkcyjny
class Macierz3x3f { //. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
float
Tab[3][3];
public :
float operator ( ) (unsigned int i, unsigned int j) const { return
Tab[ i ][ j ]; }
float& operator ( ) (unsigned int i, unsigned int j) { return
Tab[ i ][ j ]; }
}; // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
int main( )
{
Macierz3x3f M;
M(1,2) = 5
;
M(1,1) = M(1,2)
;
}
Przeci ˛
a˙zenie operatorów wywołania funkcji pozwala na organizacj ˛e wygodnego dost ˛epu do we-
wn ˛etrznych struktur tablicowych.
Przeci ˛
a˙zanie operatorów (odsłona druga)
20
Pytania i ´cwiczenia
1. Dany jest fragment kodu:
class ProstaKlasa {
int Pole;
public:
void Zmien(int Wart) { Pole = Wart; }
};
int main()
{
ProstaKlasa
const Ob;
ProstaKlasa
&Ref = Ob;
. . .
A. Czy powy˙zej w poprawny sposób utworzona została referencja do obiektu
Ob
?
B. Je˙zeli nie, to jak nale˙zy to zapisa´c aby operacja była poprawna (nie zmieniaj ˛
ac
deklaracji referencji
Ref
)?
C. Je˙zeli tak, to jak nale˙zy to zapisa´c aby uniemo˙zliwi´c tak ˛
a operacj ˛e?
D. Czy po utworzeniu referencji
Ref
b ˛edzie si ˛e mo˙zna poprzez ni ˛
a odwoła´c do me-
tody
Zmien
?
Przeci ˛
a˙zanie operatorów (odsłona druga)
21
Pytania i problemy
2. Dana jest definicja klasy
LZespolona:
class LZespolona {
public :
float
re, im;
LZespolona operator = ( LZespolona Z)
{ re = Z. re;
im = Z. im;
return
∗
this ; }
};
Niech b ˛ed ˛
a dane zmienne:
LZespolona Z1, Z2, Z3. Czy dwie poni˙zsze operacje daj ˛
a taki
sam wynik?
Z1 = Z2 = Z3;
(Z1 = Z2) = Z3;
Je˙zeli tak, to jaki zachodzi zwi ˛
azek mi ˛edzy warto´sciami zmiennych? Je˙zeli natomiast nie, to
co nale˙zy zrobi´c, aby wynik był taki sam?
3. Dana jest definicja klasy:
class LZespolona {
public :
float
re, im;
LZespolona & operator ++ (int) { ++ re; ++ im; return
∗
this ; }
};
Czy działanie przedstawione poni˙zej jest prawidłowo zapisane (w sensie składni)?
LZespolona
Z1;
Z. re = Z. im = 2; ++Z. re += 1;
Je˙zeli tak, to jaki jest wynik działania? Je˙zeli nie, to co nale˙zy zrobi´c, aby było ono poprawne.
Przeci ˛
a˙zanie operatorów (odsłona druga)