Referencje do zmiennych i obiektów Bogdan Kreczmer ZPCiR IIAiR PWr pokój 307 budynek C3 bogdan.kreczmer@pwr.wroc.pl Copyright c 2005 2008 Bogdan Kreczmer Niniejszy dokument zawiera materiały do wykładu na temat programowania obiektowego. Jest on udostępniony pod warunkiem wykorzystania wyłacznie do własnych prywatnych potrzeb i może on być kopiowany wyłacznie w całości, razem z niniejsza strona tytułowa.
Referencje do zmiennej int main( ) int Zmienna = 2; int &RefDoZm = Zmienna; RefDoZm = 4; if (Zmienna == RefDoZm) cout << O rany, wartości tych zmiennych sa równe! << endl; if (&Zmienna == &RefDoZm) cout << ALEŻ TO S... A TE SAME ADRESY!!!!! << endl; Dzięki referencji do danej zmiennej można odwoływać się na różne sposoby. Copyright c 2005 2008 Bogdan Kreczmer Referencje do zmiennych i obiektów 1
Referencja - idea możliwej implementacji int Zm1, Zm2; Zm1 = Zm2; int * wzm1, Zm2; * wzm1 = Zm2; int Zm1, &Zm2 = Zm1; Obszar kodu Obszar kodu Zm1 = Zm2; Kod operacji: X = Y Adres arg. X: &Zm1 Adres arg. X: &Zm2 Kod operacji: * X = Y Adres arg. X: &wzm1 Adres arg. X: &Zm2 Obszar kodu Kod operacji: X = Y Adres arg. X: &Zm1 Adres arg. X: &Zm2 Obszar danych Obszar danych Obszar danych Zm2 Zm2 Zm1 Zm1 wzm1 * wzm1 Copyright c 2005 2008 Bogdan Kreczmer Referencje do zmiennych i obiektów 2
Referencje do elementu tablicy int main( ) int Tablica[ROZMIAR TABLICY]; int &RefDoElem = Tablica[5]; RefDoElem = 4; // Tu tworzymy referencję do szóstego elementu. if (Tablica[5] == RefDoElem) cout << O rany, wartości sa takie same! << endl; if (Tablica + 5 == &RefDoElem) cout << ALEŻ TO S... A TE SAME ADRESY!!!!! << endl; Referencje pozwalaja na bardziej efektywny dostęp do wybranych elementów tablicy. Copyright c 2005 2008 Bogdan Kreczmer Referencje do zmiennych i obiektów 3
Parametry przekazywane przez referencję void Podstawienie( int &Param ) Param = 3202741; int main( ) int Zmienna = 999; Podstawienie( Zmienna ); if ( Zmienna == 3202741 ) cout << Faktycznie!!! Zmiany sa widoczne na zewnatrz!!! << endl; Dla parametru przekazanego przez referencję zmiany jego wartości wewnatrz funkcji sa widoczne na zewnatrz po zakończeniu jej działania. Copyright c 2005 2008 Bogdan Kreczmer Referencje do zmiennych i obiektów 4
Parametry przekazywane przez referencję void Podstawienie( const int &Param ) Param = 3202741; int main() int Zmienna = 999; // Ta operacja jest tutaj niedozwolona Podstawienie( Zmienna ); if (Zmienna == 999) cout << Tym razem nic nie uległo zmianie. << endl; Referencja z modyfikatorem const powoduje, że dana zmienna lub parametr traktowane sa jako stałe. Copyright c 2005 2008 Bogdan Kreczmer Referencje do zmiennych i obiektów 5
Sposoby przekazywania parametrów Przekazywanie parametrów przez: Pascal C C++ wartość procedure Proc(wart :integer); void Funkcja(int wart); void Funkcja(int wart); wskaźnik procedure Proc(wsk :ˆinteger); void Funkcja(int wsk); void Funkcja(int wsk); zmienna / procedure Proc(var zm :integer); void Funkcja(int& zm); referencję referencję void Funkcja(const int& st); const Referencja dostarcza efektywny i elastyczny mechanizm przekazywania parametrów. Copyright c 2005 2008 Bogdan Kreczmer Referencje do zmiennych i obiektów 6
Referencja do obiektu class ProstaKlasa //............................................................................. int Pole; public: void Zmien(int Wart) Pole = Wart; int Pobierz() const return Pole; ; //................................................................................................ int main() ProstaKlasa Ob; ProstaKlasa &RefDoOZmiennego = Ob; const ProstaKlasa &RefDoOStalego = Ob; // Tu następuje zawężenie dostępu. RefDoOZmiennego.Zmien(2); cout << RefDoOZmiennego.Pobierz() << endl; RefDoOStalego.Zmien(2); cout << RefDoOStalego.Pobierz() << endl;... // Odwołanie się do tej metody jest teraz niedozwolone. Copyright c 2005 2008 Bogdan Kreczmer Referencje do zmiennych i obiektów 7
Referencja zwracana przez funkcję int ZmGl = 10; int &RefDoZG( ) //............................................. return ZmGl; int main( ) //................................................... int ZmLo = 0; ZmLo = RefDoZG( ); ++RefDoZG( ); RefDoZG( ) = 200; cout << ZmLo: << ZmLo << endl; cout << ZmGl: << ZmGl << endl; cout << ZmGl: << ZmGl << endl; Funkcja zwracajac referencję do zmiennej globalnej daje jednocześnie możliwość bezpośredniego dostępu do niej. Wynik działania: ZmLo: 10 ZmGl: 11 ZmGl: 200 Copyright c 2005 2008 Bogdan Kreczmer Referencje do zmiennych i obiektów 8
RefDoZG( ) = 200; Jak to działa? ZmGl 11 RefDoZG( ) = 200 RefDoZG( ) 200 ZmGl 11 int& ZmGl = 200 200 ZmGl = 200 ZmGl 11 int& 200 ZmGl 200 Copyright c 2005 2008 Bogdan Kreczmer Referencje do zmiennych i obiektów 9
Referencja do obiektu int ZmGl = 11; int WartoscZG( ) return ZmGl; int main() WartoscZG( ) = 200; Funkcja zwraca wartość, a nie dostęp do innej zmiennej. Tym samym operacja przypisania nie może być wykonana. Copyright c 2005 2008 Bogdan Kreczmer Referencje do zmiennych i obiektów 10
WartoscZG( ) = 200; Dlaczego to nie działa? ZmGl 11 WartoscZG( ) WartoscZG( ) = 200 200 11 = 200 ZmGl 11 11 200 11 = 200 ZmGl 11 11 200 ZmGl 11 Copyright c 2005 2008 Bogdan Kreczmer Referencje do zmiennych i obiektów 11
l- i p-wartość Pojęcie l-wartości przypisania. i p-wartości zwiazane jest z operacja l-wartość = p-wartość l-wartość nazwana pojedyncza zmienna reprezentujaca obszar pamięci przeznaczony do przechowywania zmiennej. p-wartość stała lub zmienna lub wyrażenie zwracajace wartość. Copyright c 2005 2008 Bogdan Kreczmer Referencje do zmiennych i obiektów 12
Referencja do obiektu int ZmGl = 11; const int& RefDoStalejZG( ) return ZmGl; int main() const int Zm = 1; Zm = 200; RefDoStalejZG( ) = 200; Nie każda l-wartość musi być modyfikowalna. Z tego powodu wyróżnia się l-wartości i l-wartości modyfikowane. Jednak często pojęcie l-wartości modyfikowalnej jest utożsamiane z l-wartościa. Copyright c 2005 2008 Bogdan Kreczmer Referencje do zmiennych i obiektów 13
Zwracanie referencji int ZmGl = 11; const int& RefDoStalejZG( ) return ZmGl; int main() const int Zm = 1; (int&)zm = 200; const cast<int&>(zm) = 200; (int&)refdostalejzg( ) = 200; const cast<int&>(refdostalejzg( )) = 200; // Rzutowanie w C Rzutowanie w C++ Stałość obiektu dostępnego poprzez wskaźnik lub referencję zawsze można ominać dokonujac odpowiedniego rzutowania. Jednak nie należy nadużywać tego mechanizmu. Zazwyczaj świadczy to o błędach koncepcyjnych w przyjętej reprezentacji danych. Copyright c 2005 2008 Bogdan Kreczmer Referencje do zmiennych i obiektów 14
Zwracanie referencji int & RefDoParam( int & Param ) return Param; int main() int ZmLo = 1; RefDoParam( ZmLo ) = 200; cout << ZmLo; Zwracanie przez funkcję referencji do obiektu ma sens w przypadku, gdy obiekt istnieje przed wywołaniem funkcji lub jest tworzony w niej w sposób dynamiczny. Copyright c 2005 2008 Bogdan Kreczmer Referencje do zmiennych i obiektów 15
Jak nie należy robić int &RefDoZmAuto( ) //................................................. int ZmAuto = 6; return ZmAuto; int &RefDoKopiiParam(int Param) //.................................... return Param; int main( ) //............................................................ int ZmLo = 1; RefDoZmAuto( ) = 200; RefDoParam( ZmLo ) = 200; cout << RefDoZmAuto( ) << endl; cout << RefDoParam( ) << endl; Błędem jest zwracanie referencji do obiektów tworzonych lokalnie. W pierwszym przypadku jest to zmienna automatyczna, zaś w drugim kopia parametru. Wynik działania programu: 134515632 134520592 Copyright c 2005 2008 Bogdan Kreczmer Referencje do zmiennych i obiektów 16
Referencja do pola klasy class PrzykladKlasyA //.......................................... int PoleKlasy; public : int & PoleModyf( ) return PoleKlasy; const int & PoleStale( ) const return PoleKlasy; ; //................................................................. int main( ) int ZmLo = 0; PrzykladKlasyA ObiektA; ZmLo = ObiektA.PoleStale( ); ZmLo = ObiektA.PoleModyf( ); ObiektA.PoleModyf( ) = ZmLo; Udostępnianie możliwości modyfikacji zawartości pola klasy poprzez zwrócenie przez metodę referencji nie jest częsta praktyka. Znajduje to jednak zastosowanie w przypadku przeciażeń operatorów. Copyright c 2005 2008 Bogdan Kreczmer Referencje do zmiennych i obiektów 17
Referencja do obiektu class PrzykladKlasyB //.................................................. public : int PoleKlasy; PrzykladKlasyB & ObiektModyf( ) return this ; const PrzykladKlasyB & ObiektStaly( ) const return this ; //.......................................................................... int main( ) int ZmLo = 0; PrzykladKlasyB ObiektB; ZmLo = ObiektB.ObiektStaly( ). PoleKlasy; ZmLo = ObiektB.ObiektModyf( ). PoleKlasy; ObiektB.ObiektModyf( ). PoleKlasy = ZmLo; Udostępnianie możliwości modyfikacji obiektu poprzez zwrócenie przez metodę referencji może być użyteczne, gdy dopuszcza się możliwość wywołań wielu metod dla tego samego obiektu. Copyright c 2005 2008 Bogdan Kreczmer Referencje do zmiennych i obiektów 18
Problem parametrów nazwanych class WekParam //................................................................... public : float x, y, z; WekParam( ) x = y = z = 0; WekParam &X(float x) x = x; return this ; WekParam &Y(float y) y = y; return this ; WekParam &Z(float z) z = z; return this ; ; //..................................................................................... class Wektor3f //.................................................................... float x, y, z; public : void Zmien( const WekParam& P ) x = P. x; y = P. y; z = P. z; //...................................................................................... int main( ) Wektor3f W; W.Zmien( WekParam( ).X(1).Z(10) ); Parametry nazwane w sposób pośredni moga być realizowane w ramach składni C++. Copyright c 2005 2008 Bogdan Kreczmer Referencje do zmiennych i obiektów 19
Bezpośrednia zmiana wybranych parametrów class Wektor3f //......................................................... float x, y, z; public : Wektor3f( ) x = y = z = 0; Wektor3f &X(float x) x = x; return this ; Wektor3f &Y(float y) y = y; return this ; Wektor3f &Z(float z) z = z; return this ; //.......................................................................... int main( ) Wektor3f W; W.X(1).Z(10); W trakcie prac nad standardem języka C++ powstał pomysł wprowadzenia parametrów nazwanych jako dodatkowej konstrukcji. Przykład, którego idea podana jest na poprzednim slajdzie, był argumentem świadczacym o tym, że istniejace mechanizmy umożliwiaja realizację tej konstrukcji bez potrzeby wprowadzania dodatkowych elementów składni. Copyright c 2005 2008 Bogdan Kreczmer Referencje do zmiennych i obiektów 20
Pytania i ćwiczenia Dany jest fragment kodu: class ProstaKlasa int Pole; public: void Zmien(int Wart) Pole = Wart; ; int main() ProstaKlasa const Ob; ProstaKlasa &Ref = Ob;... 1. Czy powyżej w poprawny sposób utworzona została referencja do obiektu Ob? 2. Jeżeli nie, to jak należy to zapisać aby operacja była poprawna (nie zmieniajac deklaracji referencji Ref)? 3. Jeżeli tak, to jak należy to zapisać aby uniemożliwić taka operację? 4. Czy po utworzeniu referencji Ref będzie się można poprzez nia odwołać do metody Zmien? Copyright c 2005 2008 Bogdan Kreczmer Referencje do zmiennych i obiektów 21