NazWektor
Transkrypt
NazWektor
Wyliczanie wyrażenia – obiekty tymczasowe Bogdan Kreczmer ZPCiR IIAiR PWr pokój 307 budynek C3 [email protected] c 2013 Bogdan Kreczmer? Copyright ? Niniejszy dokument zawiera materiały do wykładu na temat programowania obiektowego. Jest on udostepniony ˛ pod warun- kiem 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. ˛ Czas życia obiektów tymczasowych int main( ) { NazWektor W a(”a”, 1, 2), W b(”b”, 1, 1), W c(”c”, 1, 0), W d(”d”, 2, 2), W r(”r”); cout << ”—- Poczatek operacji dodawania —————–” << endl; W r = (W a + W b) + (W c + W d); cout << ”—- Koniec operacji dodawania ——————-” << endl; cout << ”—- Rezultat: ” << W r << endl; } Wykonywaniu poszczególnych operacji towarzyszy tworzenie sie˛ obiektów tymczasowych. Chcac ˛ prześledzić ten proces, należy przeciażyć ˛ odpowiednie konstruktory. Przeciażenia ˛ te musza˛ zapewniać możliwość nazwania obiektów, tak aby można było prześledzić okres życia poszczególnych obiektów. c 2013 Bogdan Kreczmer Copyright Wyliczanie wyrażenia – obiekty tymczasowe 1 Czas życia obiektów tymczasowych class NazWektor { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . static char ZnakCyfry; public : string Nazwa; float x, y; NazWektor(const char ∗Nazwa, float x = 0, float y = 0 ); NazWektor( const NazWektor & W ); ∼ NazWektor( ); NazWektor operator + ( const NazWektor & W ) const; NazWektor & operator = ( const NazWektor & W ); }; . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . char NazWektor:: ZnakCyfry = ’0’; int main( ) { NazWektor W( ”a” , 1, 2 ); } ostream & operator << ( ostream & ostrm, const NazWektor & W ) { return ostrm << W. Nazwa << ”(” << W. x << ”, ” << W. y << ”)”; } cout << W << endl; Wynik działania: a(1, 2) Wprowadzenie dodatkowego pola statycznego pozwala numerować tworzace ˛ sie˛ tymczasowe obiekty. Zaś pole Nazwa pozwala nazywać każdy z obiektów. c 2013 Bogdan Kreczmer Copyright Wyliczanie wyrażenia – obiekty tymczasowe 2 Definicje konstruktora i destruktora class NazWektor { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . static char ZnakCyfry; public : string Nazwa; float x, y; NazWektor(const char ∗Nazwa, float x = 0, float y = 0 ); ... ∼ NazWektor( ); ... }; . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . NazWektor::NazWektor( const char ∗Nazwa, float x, float y ): Nazwa(Nazwa) { x = x; y = y; cout << ”++ Konstruktor: ” << ∗this << endl; int main( ) { } NazWektor W( ”a” , 1, 2 ); } NazWektor::∼ NazWektor( ) { cout << ”++ Destruktor: ” << ∗this << endl; } Wynik działania: ++ Konstruktor: a(1, 2) −− Destruktor: a(1, 2) Wywołanie konstruktora lub destruktora jest sygnalizowane odpowiednim komunikatem na wyjściu standardowym. Podaje on nazwe˛ i wartości pól obiektu. c 2013 Bogdan Kreczmer Copyright Wyliczanie wyrażenia – obiekty tymczasowe 3 Konstruktor kopiujacy ˛ class NazWektor { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . static char ZnakCyfry; public : string Nazwa; x, y; float ... NazWektor( const NazWektor & W ); ... }; . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . NazWektor::NazWektor( const NazWektor & W ): Nazwa(”Tmp”) { Nazwa += ++ ZnakCyfry; x = y = 0; cout << ”.. Kopiuje: ” << ∗this << ” <- ” << W << endl; x = W. x; y = W. y; } int main( ) { NazWektor W( ”a” , 1, 2 ); NazWektor V(W); } Wynik działania: ++ Konstruktor: a(1, 2) ++ Kopiuje: Tmp1(0,0) <- a(1, 2) −− Destruktor: Tmp1(1, 2) −− Destruktor: a(1, 2) Konstruktor kopiujacy ˛ w tym rozwiazaniu ˛ nie powoduje przepisanie nazwy obiektu. Jest to niezbedne, ˛ aby móc zidentyfikować nowy obiekt. Jego nazwa tworzona jest automatycznie. c 2013 Bogdan Kreczmer Copyright Wyliczanie wyrażenia – obiekty tymczasowe 4 Operator dodawania class NazWektor { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . static char ZnakCyfry; public : string Nazwa; x, y; float ... NazWektor operator + ( const NazWektor& W ) const; ... }; . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . NazWektor NazWektor::operator + ( const NazWektor& W ) const { cout << ”.. Dodanie: ” << ∗this << ” + ” << W << endl; string Nazwa( ”Tmp” ); Nazwa += ++ ZnakCyfry; return NazWektor( Nazwa.c str(), x+W. x, y+W. y ); } int main( ) { NazWektor W( ”a” , 1, 2 ); W = W + W; } Wynik działania: ++ Konstruktor: .. Dodanie: a(1, ++ Konstruktor: −− Destruktor: −− Destruktor: a(1, 2) 2) + a(1,2) Tmp1(2, 4) Tmp1(2, 4) a(1, 2) W trakcie realizacji operacji dodawania tworzony jest obiekt tymczasowy, który przekazuje ”na zewnatrz” ˛ wynik działania. c 2013 Bogdan Kreczmer Copyright Wyliczanie wyrażenia – obiekty tymczasowe 5 Operator przypisania class NazWektor { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . static char ZnakCyfry; public : string Nazwa; x, y; float ... NazWektor & operator = ( const NazWektor & W ); ... }; . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . NazWektor & NazWektor::operator = ( const NazWektor & W ) { cout << ”.. Podstawienie: ” << ∗this << ” = ” << W << endl; x = W. x; y = W. y; return ∗this ; } int main( ) { NazWektor W( ”a” , 1, 2 ); W = W; } Wynik działania: ++ Konstruktor: a(1, 2) .. Podstawienie: a(1, 2) = a(1,2) −− Destruktor: a(1, 2) Realizacja operacji podstawienia nie wymaga tworzenia żadnych obiektów tymczasowych. Zarówno argument, jak też wynik działania, zwracane sa˛ przez referencje. c 2013 Bogdan Kreczmer Copyright Wyliczanie wyrażenia – obiekty tymczasowe 6 W r = (W a + W b) + (W c + W d) class NazWektor { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . static char ZnakCyfry; public : string Nazwa; float x, y; NazWektor(const char ∗Nazwa, float x = 0, float y = 0); NazWektor( const NazWektor & W ); ∼ NazWektor( ); NazWektor operator + ( const NazWektor & W ) const; NazWektor & operator = ( const NazWektor & W ); }; . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ... int main() { NazWektor Wa(”a”,1,2), Wb(”b”,1,1), Wc(”c”,1,0), Wd(”d”,2,2); NazWektor Wr(”r”); cout << ”— Poczatek operacji dodawania ——-” << endl; Wr = (Wa + Wb) + (Wc + Wd); cout << ”— Koniec operacji dodawania ———-” << endl; cout << ”— Rezultat: ” << Wr << endl; } c 2013 Bogdan Kreczmer Copyright Wynik działania: ++ Konstruktor: ++ Konstruktor: ++ Konstruktor: ++ Konstruktor: ++ Konstruktor: a(1, 2) b(1, 1) c(1, 0) d(2, 2) r(0, 0) — Poczatek operacji dodawania ———.. Dodanie: c(1, 0) + d(2, 2) ++ Konstruktor: Tmp1(3, 2) .. Dodanie: a(1, 2) + b(1, 1) ++ Konstruktor: Tmp2(2, 3) .. Dodanie: Tmp2(2, 3) + Tmp1(3, 2) ++ Konstruktor: Tmp3(5, 5) .. Podstawienie: r(0, 0) = Tmp3(5, 5) ++ Destruktor: Tmp3(5, 5) ++ Destruktor: Tmp2(2, 3) ++ Destruktor: Tmp1(3, 2) — Koniec operacji dodawania ———— — Rezultat: r(5, 5) ++ Destruktor: ++ Destruktor: ++ Destruktor: ++ Destruktor: ++ Destruktor: r(5, 5) d(2, 2) c(1, 0) b(1, 1) a(1, 2) Wyliczanie wyrażenia – obiekty tymczasowe 7 W r = (W a + W b) + (W c + W d) ... — Poczatek operacji dodawania ———.. Dodanie: c(1, 0) + d(2, 2) W r = (W a + W b) + (W c + W d); ⇓ ++ Konstruktor: Tmp1(3, 2) .. Dodanie: a(1, 2) + b(1, 1) W r = (W a + W b) + W r = (W a + W b) + Tmp1 Tmp1 ; ; Tmp1 Tmp1 ; ; ⇓ ++ Konstruktor: Tmp2(2, 3) .. Dodanie: Tmp2(2, 3) + Tmp1(3, 2) W r= W r= Tmp2 Tmp2 + + ⇓ ++ Konstruktor: Tmp3(5, 5) .. Podstawienie: r(0, 0) = Tmp3(5, 5) ++ Destruktor: Tmp3(5, 5) ++ Destruktor: Tmp2(2, 3) ++ Destruktor: Tmp1(3, 2) W r= W r= W r Tmp3 Tmp3 ; ; −→; — Koniec operacji dodawania ———— — Rezultat: r(5, 5) ... W trakcie realizacji całej operacji tworza˛ sie˛ obiekty pośrednie, które przekazuja˛ wyniki cz˛eściowe. Wszystkie one kończa˛ swoje istnienie wraz z zakończeniem realizacji danej operacji, tzn. wtedy gdy sterowanie ”przekroczy” znak średnika. c 2013 Bogdan Kreczmer Copyright Wyliczanie wyrażenia – obiekty tymczasowe 8 Zapobieganie tworzeniu obiektów tymczasowych class Wektor3f { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . public : float x, y; NazWektor3f operator + ( Wektor3f W ) const { return W += ∗this ; } Wektor3f & operator += ( const Wektor3f & W ) { x += W. x; y = W. y; return ∗this ; } }; . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Wektor3f W1, W2, W3; W1 = W2 + W3; Ilość obiektów tymczasowych: 2 =⇒ (W1 = W2) += W3; Ilość obiektów tymczasowych: 0 Stosujac ˛ bardziej przemyślany zapis operacji arytmetycznych można całkowicie wyeliminować tworzenie sie˛ obiektów tymczasowych. c 2013 Bogdan Kreczmer Copyright Wyliczanie wyrażenia – obiekty tymczasowe 9 Podsumowanie Przy stosowaniu przeciaże ˛ ń operatorów zapis złożonych działań zazwyczaj wiaże ˛ sie˛ z powstawaniem obiektów tymczasowych. Ich liczbe˛ można prawie zawsze ograniczyć lub całkowicie je wyeliminować. Powoduje to jednak utrate˛ czytelności zapisu takiego działania. W przypadku gdy wymagania czasowe nie sa˛ krytyczne właściwym może być zachowanie przejrzystości zapisu kosztem efektywności wykonywanych operacji. Takie podejście jest szczególnie pomocne w poczatkowej ˛ fazie tworzenia oprogramowania, gdyż zapobiega powstawaniu przypadkowych błedów ˛ w implementowanych wzorach. c 2013 Bogdan Kreczmer Copyright Wyliczanie wyrażenia – obiekty tymczasowe 10 Pytania i ćwiczenia 1. Jeżeli byłaby możliwa nastepuj ˛ aca ˛ definicja konstruktora kopiujacego ˛ kopiujacego: ˛ class Klasa { public: Klasa( Klasa Ob ) { } }; to jakie byłyby konsekwencje w momencie jego użycia. 2. Zakładajac, ˛ że klasa Wektor3f jest tak samo zdefiniowana jak w prezentowanym wcześniej przykładzie, należy wyznaczyć liczbe˛ powstajacych ˛ obiektów tymczasowych dla wyrażenia: Wr = Wa + Wb + Wc + Wd; c 2013 Bogdan Kreczmer Copyright Wyliczanie wyrażenia – obiekty tymczasowe 11