Wykład 2 Klasa Zesp i jej hermetyzacja 1.Przykład definicji klasy Zesp 2.Zmiana definicji klasy 3.Zmienne i funkcje statyczne PO2-1 / 28
Klasa Zesp Przykład definicji klasy i jej hermetyzacji PO2-2 / 28
Liczba zespolona Z( Re, Im ) Re Im Algorytmy (przykładowe): konstruktory liczby Z, obliczanie Realis liczby Z, obliczanie Imaginary liczby Z, dodawanie Z 1 +Z 2, mnożenie Z 1 *Z 2, dzielenie Z 1 /Z 2, wprowadzanie liczby Z, wyprowadzanie liczby Z. Dane: Re, Im PO2-3 / 28
class Zesp { private: double Re, Im; public: Zesp(double=0, double=0);// konstruktor Zesp operator +(const Zesp&) const; double Realis( ) const {// definicja funkcji Realis return Re; } friend ostream &operator<<(ostream&, const Zesp&); }; Klasa Zesp - początek Algorytmy: konstruktory liczby Z, obliczanie Realis liczby Z, dodawanie Z 1 +Z 2, wyprowadzanie liczby Z. PO2-4 / 28
class Zesp { //... Zesp operator +(const Zesp&) const; friend ostream &operator<<(ostream&, const Zesp&); }; Operatory + oraz << V = Z. operator +( W ); Zesp Z, W, V; //... V = Z + W; cout << V; cout. operator <<( V ); operator <<( cout, V ); Funkcja operator << nie może być metodą klasy Zesp, bo cout nie jest obiektem klasy Zesp. Nie może być też metodą klasy ostream, bo niczego w tej klasie nie wolno nam zmieniać. Zatem funkcja operator << musi być funkcją globalną. PO2-5 / 28
#ifndef _INC_ZespClass // Aby zapobiec wielokrotnemu #define _INC_ZespClass // włączaniu treści tego pliku // podczas kompilacji #include class Zesp { private: double Re, Im; public: Zesp(double=0, double=0);// konstruktor Zesp operator +(const Zesp&) const; double Realis( ) const { return Re; } friend ostream &operator<<(ostream&, const Zesp&); }; #endif // koniec #ifndef _INC_ZespClass Plik zesp.h PO2-6 / 28
Zesp::Zesp(double Re, double Im):Re( Re ), Im( Im ) { } Konstruktor klasy Zesp main(void) { Zesp A(1.23, 3.14);// A=Zesp(1.23, 3.14); Zesp B(10, 20); // B=Zesp(10, 20); Zesp C; // C=Zesp( ); Zesp D(2.51); // D=Zesp(2.51);... } class Zesp { double Re, Im;... Zesp(double=0, double=0);// konstruktor... }; PO2-7 / 28
Zesp Zesp::operator +(const Zesp &b) const { return Zesp( Re +b.Re, Im +b.Im); } Dodawanie ( Re+jIm) + ( b.Re+jb.Im) = ( Re+b.Re) + j( Im+b.Im) ReIm ( x 1 +j y 1 ) + ( x 2 +j y 2 ) = (x 1 +x 2 ) + j( y 1 +y 2 ) PO2-8 / 28
#include "zesp.h" Zesp::Zesp(double Re, double Im):Re(Re), Im(Im) { } Zesp Zesp ::operator+(const Zesp &b) const { return Zesp(Re+b.Re, Im+b.Im); } ostream &operator<<(ostream &wy, const Zesp &z) {return wy<<setprecision(3)<<'('<<z.Re<<", "<<z.Im<<')'; } Plik zesp.cpp Plik prog.cpp #include "zesp.h" Zesp::Zesp(double Re, double Im):Re(Re), Im(Im) { // Zesp::Re=Re, Zesp::Im=Im } Zesp Zesp::operator +(const Zesp &b) const { return Zesp( Re +b.Re, Im +b.Im); } ostream &operator<<(ostream &wy, const Zesp &z) {return wy<<setprecision(3)<<'('<<z.Re<<", "<<z.Im<<')'; } #include "zesp.h" main( ) {Zesp A(1.23, 3.14), B(10, 20), C; C=A+B;// C=A.operator+(B); cout << C; // operator<<(cout, C); return(0); } PO2-9 / 28
class Zesp { //... Zesp operator*(const Zesp&) const; Zesp operator /(const Zesp&) const; double Imaginary( ) const {// definicja funkcji Imaginary return Im; } friend istream &operator>>(istream&, Zesp&); }; Dalsze funkcje klasy Zesp Algorytmy: obliczanie Imaginary liczby Z, mnożenie Z 1 *Z 2, dzielenie Z 1 /Z 2, wprowadzanie liczby Z. PO2-10 / 28
Zesp Zesp::operator *(const Zesp &b) const { return Zesp( Re*b.Re – Im*b.Im, Re*b.Im +Im*b.Re); } Mnożenie ( Re+jIm)*( b.Re+jb.Im) = = ( Re*b.Re–Im*b.Im)+j(Re*b.Im+Im*b.Re) ReIm ( x 1 +j y 1 ) * ( x 2 +j y 2 ) = ( x 1 x 2 – y 1 y 2 ) + j( x 1 y 2 + x 2 y 1 ) PO2-11 / 28
Zesp Zesp::operator /(const Zesp &b) const { double r = b.Re*b.Re + b.Im*b.Im; return Zesp(( Re*b.Re + Im*b.Im)/r, (Im*b.Re – Re*b.Im)/r); } Dzielenie ( Re+jIm)/( b.Re+jb.Im) = ReIm x 1 +j y 1 x 2 +j y 2 ( x 1 x 2 + y 1 y 2 ) + j( x 2 y 1 –x 1 y 2 ) x y 2 2 = Re*b.Re+Im*b.Im ( b.Re) 2 + ( b.Im) 2 Im*b.Re – Re*b.Im ( b.Re) 2 + ( b.Im) 2 =+j PO2-12 / 28
istream &operator >>(istream &we, Zesp &z) { int k = we = = cin; // wejście z klawiatury if ( k ) cerr << "Re= "; we >> z.Re; if ( k ) cerr << "Im= "; we >> z.Im; return we; } Wprowadzanie Re= _Re= 3.75 Im= _ Re= 3.75 Im= 7.5 _ PO2-13 / 28
Plik prog.cpp #include "zesp.h" #include "zesp.cpp" main( ) {Zesp A(1.23, 3.14), B(10, 20), C; C=A+B;// C=A.operator+(B); cout << C; // operator<<(cout, C); cout << endl; cerr << "Podaj kolejno A i B"; cin >> A; // operator>>(cin, A); cin >> B; // operator>>(cin, B); C=A*B;// C=A.operator*(B); cout <<"A*B="<< C << endl; cout <<"A/B="<< (A/B) << endl; return(0); } P02-14 / 28
Nowa klasa Zesp Przykład zmiany definicji klasy PO2-15 / 28
Modyfikacja klasy ( Re, Im ) Re Im ( r, fi ) Re Im r fi Re = r cos( fi ) Im = r sin( fi ) PO2-16 / 28
#ifndef _INC_ZespClass #define _INC_ZespClass #include class Zesp { private: double r, fi; public: Zesp(double=0, double=0); Zesp operator +(const Zesp&) const; Zesp operator *(const Zesp&) const; Zesp operator /(const Zesp&) const; double Realis( ) const { return r*cos( fi ); } double Imaginary( ) const { return r*sin( fi ); } friend ostream &operator <<(ostream&, const Zesp&); friend istream &operator >>(istream&, Zesp&); }; #endif // koniec #ifndef _INC_ZespClass Plik zesp.h PO2-17 / 28
Plik zesp.cpp #include "zesp.h" #include "math.h" Zesp Zesp::operator +(const Zesp &b) const { return Zesp(r*cos(fi)+b.r*cos(b.fi), r*sin(fi)+b.r*sin(b.fi) ); } Zesp::Zesp(double Re, double Im):r(sqrt(Re*Re+Im*Im)), fi(r?atan2(Re, Im):0) { } Zesp Zesp::operator *(const Zesp &b) const { Zesp Z; Z.r = r * b.r ; Z.fi = fi + b.fi ; return Z ; } PO2-18 / 28
Plik zesp.cpp – c.d. Zesp Zesp::operator /(const Zesp &b) const { Zesp Z; Z.r = r / b.r ; Z.fi = fi – b.fi ; return Z ; } ostream &operator<<(ostream &wy, const Zesp &z) { return wy<<setprecision(3)<<'('<<z.r*cos(z.fi) <<", "<<z.r*sin(z.fi)<<')'; } PO2-19 / 28
Plik zesp.cpp – c.d. istream &operator>>(istream &we, Zesp &z) { int k = we = = cin; // wejście z klawiatury double Re, Im; if ( k ) cerr << "Re= "; we >> Re; if ( k ) cerr << "Im= "; we >> Im; z.r = sqrt( Re*Re + Im*Im ); z.fi = z.r ? atan2( Re, Im ) : 0; return we; } PO2-20 / 28
Porównajmy funkcje Zesp::Zesp(double Re, double Im): r(sqrt(Re*Re+Im*Im)), fi(r?atan2(Re, Im):0) { } PO2-21 / 28 Zesp::Zesp(double Re, double Im): Re(Re), Im(Im) { // Zesp::Re=Re, Zesp::Im=Im } Zesp Zesp::operator +(const Zesp &b) const { return Zesp(r*cos(fi)+b.r*cos(b.fi), r*sin(fi)+b.r*sin(b.fi) ); } Zesp Zesp::operator +(const Zesp &b) const { return Zesp( Re +b.Re, Im +b.Im); }
Porównajmy funkcje PO2-22 / 28 Zesp Zesp::operator *(const Zesp &b) const { return Zesp( Re*b.Re – Im*b.Im, Re*b.Im +Im*b.Re); } Zesp Zesp::operator *(const Zesp &b) const { Zesp Z; Z.r = r * b.r ; Z.fi = fi + b.fi ; return Z ; }
Porównajmy funkcje PO2-23 / 28 ostream &operator<<(ostream &wy, const Zesp &z) {return wy<<setprecision(3)<<'('<<z.Re<<", "<<z.Im<<')'; } ostream &operator<<(ostream &wy, const Zesp &z) { return wy<<setprecision(3)<<'('<<z.r*cos(z.fi) <<", "<<z.r*sin(z.fi)<<')'; }
Plik prog.cpp #include "zesp.h" #include "zesp.cpp" main( ) {Zesp A(1.23, 3.14), B(10, 20), C; C=A+B;// C=A.operator+(B); cout << C; // operator<<(cout, C); cout << endl; cerr << "Podaj kolejno A i B"; cin >> A; // operator>>(cin, A); cin >> B; // operator>>(cin, B); C=A*B;// C=A.operator*(B); cout <<"A*B="<< C << endl; cout <<"A/B="<< (A/B) << endl; return(0); } PO2-24 / 28 Dzięki hermetyzacji klasy plik ten pozostał bez zmian.
Zmienne i funkcje statyczne PO2-25 / 28
class Zesp { private: double Re, Im; // albo double r, fi; static int N; // deklaracja zmiennej statycznej public: static int Ile( ) { return N; } // funkcja statyczna //... }; Zmienne i funkcje statyczne #include "zesp.h" int Zesp::N=0; // definicja zmiennej statycznej main( ) { Zesp A, B, C; int n = Zesp::Ile( ); // wywołanie funkcji statycznej //... } PO2-26 / 28
Zmienne i funkcje statyczne int Zesp::N=0; // definicja zmiennej statycznej main( ) { Zesp A, B, C; int n = Zesp::Ile( ); // wywołanie funkcji statycznej n = A.Ile( ); // wywołanie funkcji statycznej z klasy // obiektu A, ale nie do obiektu A //... } ARe Im BRe Im CRe Im Zesp::N Zmienna statyczna N występuje poza obiektami i jest wspólna wszystkim obiektom swojej klasy. Np. wyrażenia A.N, B.N oraz C.N oznaczają tę samą zmienną Zesp::N. PO2-27 / 28
Przykład zastosowania Wykorzystajmy zmienną statyczną N do liczenia obiektów. Wszystkie konstruktory powinny zwiększać wartość, natomiast destruktor powinien zmniejszać wartość zmiennej N. Trzeba zatem zdefiniować: Zesp::Zesp(double Re, double Im):Re(Re), Im(Im) // albo r(sqrt(Re*Re+Im*Im)), fi(r?atan2(Re, Im):0) { ++N; } // konstruktor kopiujący Zesp::Zesp(const Zesp &z):Re(z.Re), Im(z.Im) // albo r(z.r), fi(z.fi) { ++N; } Zesp::~Zesp( ) // destruktor { – –N; } O ile nie będziemy jawnie wywoływać destruktora do obiektów oraz N zainicjujemy zerem, N będzie równe liczbie obiektów. PO2-28 / 28