Programowanie

Projekt klasy

(język C++)

Vector

Wykład 6.

c.d.

Tomasz Marks - Wydział MiNI PW

-1-

Tomasz Marks - Wydział MiNI PW

-2-

Projekt klasy Vector – uŜycie [3]

Projekt klasy Vector – uŜycie [4]

int main ( )

int main ( )

{

{

Vector v1 ( 3, 20. ), v2 ( 5, 10. ), v3;

Vector v1 ( 3, 20. ), v2 ( 5, 10. ), v3;

v3 = v1 + v2;

v3 = v1 + v2; // v3 = operator+ ( v1, v2 );

cout << v1 << v2 << v3; // 20 20 20

cout << v1 << v2 << v3; // 20 20 20

// 10 10 10 10 10

// 10 10 10 10 10

// 30 30 30 10 10

// 30 30 30 10 10

v3 = v1 + 2;

v3 = v1 + 2; // v3 = operator+ ( v1, Vector(2) );

cout << v3; // 20 20 20

cout << v3; // 20 20 20

v3 = v1 + 5;

v3 = v1 + 5;

// v3 = operator+ ( v1, Vector(5) );

cout << v3; // 20 20 20 0 0

cout << v3; // 20 20 20 0 0

v3 = 10.2 + v1;

v3 = 10.2 + v1; // v3 = operator+ ( Vector( int(10.2) ), v1 ); cout << v3; // 20 20 20 0 0 0 0 0 0 0

cout << v3; // 20 20 20 0 0 0 0 0 0 0

Tomasz Marks - Wydział MiNI PW

-3-

Tomasz Marks - Wydział MiNI PW

-4-

Projekt klasy Vector – uŜycie [5]

UWAGA:

Aby się ustrzec przed tego typu niespodziankami, naleŜ y zadeklarować int main ( )

konstruktor, który moŜ na wywołać z jednym argumentem typu int , jako

{

Vector v1 ( 3, 20. ), v2 ( 5, 10. ), v3;

explicit Vector ( int size, double val=0 );

double ilskal;

co zabrania uŜ ycia konstruktora dla niejawnej konwersji parametrów, ilskal = v1 * v2; // ilskal = operator* ( v1, v2 ); i przewidzieć funkcje dla innych układów parametrów, oprócz: cout << v1 << v2 << ilskal; // 20 20 20

// 10 10 10 10 10

friend Vector operator + ( const Vector& a, const Vector& b );

// 600

friend Vector operator * ( double k, const Vector& a );

v3 = 2 * v1; // v3 = operator* ( double(2), v1 ); friend double operator * ( const Vector& a, const Vector& b ); cout << v3; // 40 40 40

równieŜ

ilskal = v1 * 5.2; // ilskal = operator*(v1, Vector(int(5.2))); cout << ilskal; // 0

friend Vector operator + ( double a, const Vector& b );

friend Vector operator + ( const Vector& a, double b );

……………………………

friend Vector operator * ( const Vector& a, double k );

Tomasz Marks - Wydział MiNI PW

-5-

Tomasz Marks - Wydział MiNI PW

-6-

Problem projektowy

DANE WEJŚ CIOWE:

Dysponujemy dobrze zdefiniowaną i przetestowaną klasą Vector , która faktycznie pozwala na operowanie dynamicznie alokowanymi

Nowy

tablicami danych liczbowych.

ZADANIE:

problem projektowy

Chcemy operować wektorami, które zwią zane bę dą z pewnymi zadawanymi dowolnie jednostkami fizycznymi ( n.p. [m], [m/s],

[m/s2], [A], [V] ).

Dla uproszczenia załoŜ ymy, Ŝ e wszystkie współrzę dne wektora zwią zane są z tą samą jednostką .

Klasę nazwiemy PhVector X

Prześ ledzimy dwa sposoby podejś cia do tego problemu definiują c dwie klasy: PhVectorA i PhVectorB .

Tomasz Marks - Wydział MiNI PW

-7-

Tomasz Marks - Wydział MiNI PW

-8-

Klasa z polem składowym typu Vector [1]

// phvectora.h

#include "vector.h"

Klasa

#define U_LEN 10

class PhVectorA

{

public:

z polem składowym

Vector W;

private:

char Unit [ U_LEN ];

public:

typu Vector

PhVectorA ( int = 0, double* = 0, char* = "" );

PhVectorA ( const PhVectorA& );

~PhVectorA ( );

PhVectorA& operator = ( const PhVectorA& );

void setUnit ( char* );

char* getUnit ( ) const;

friend istream& operator >> ( istream&, PhVectorA& ); friend ostream& operator << ( ostream&, const PhVectorA& );

};

Tomasz Marks - Wydział MiNI PW

-9-

Tomasz Marks - Wydział MiNI PW

-10-

Klasa z polem składowym typu Vector [2]

PhVectorA – implementacje [1]

// phvectora.h

#include "vector.h"

#define U_LEN 10

// phvectora.cpp

class PhVectorA

{

#include <cstring> // ew. <string.h> jak w jęz. C

public:

// niektóre kompilatory pozwalają pomijać

Vector W;

// pliki nagłówkowe 'odziedziczone' z C

private:

char Unit [ U_LEN ];

#include "phvectora.h"

public:

PhVectorA ( int = 0, double* = 0, const char* = "" ); const char* PhVectorA::getUnit ( ) const

PhVectorA ( const PhVectorA& );

{ return Unit; }

~PhVectorA ( );

PhVectorA& operator = ( const PhVectorA& );

void PhVectorA::setUnit ( const char* str )

void setUnit ( const char* );

{ strncpy ( Unit, str, U_LEN ); }

const char* getUnit ( ) const;

friend istream& operator >> ( istream&, PhVectorA& );

………………………………………………………...

friend ostream& operator << ( ostream&, const PhVectorA& );

…………………………………………………………

};

Tomasz Marks - Wydział MiNI PW

-11-

Tomasz Marks - Wydział MiNI PW

-12-

PhVectorA – implementacje [2]

PhVectorA – implementacje [3]

PhVectorA::PhVectorA ( int s, double tab[ ], char* u )

PhVectorA::PhVectorA ( int s, double tab[ ], char* u ) : W ( s, tab )

{

{

// składowa W juŜ istnieje zainicjowana

// składowa W juŜ istnieje zainicjowana

// wywołaniem konstruktora Vector ( )

// wywołaniem konstruktora Vector ( s, tab )

strncpy ( Unit, u, U_LEN );

strncpy ( Unit, u, U_LEN );

// jak "przewymiarować" składową W, by miała rozmiar s

// i nic więcej nie trzeba robić !!!

// i była zapełniona wartościami z tablicy tab ???

}

………………………………………………………...

…………………………………………………………

Tomasz Marks - Wydział MiNI PW

-13-

Tomasz Marks - Wydział MiNI PW

-14-

Lista inicjacyjna konstruktora [1]

Lista inicjacyjna konstruktora [2]

UŜ ycie listy inicjacyjnej nie ogranicza się do inicjowania składowych Definicja konstruktora postaci

obiektowych, n.p. zamiast

Class::Class ( ListaParametrów ) : ListaInicjacyjna { …. }

CMPLX::CMPLX ( double re, double im )

{ Re = re; Im = im; }

gdzie ListaParametrów i ListaInicjacyjna mogą być puste, moŜ emy napisać

jest równowaŜ na definicji

CMPLX::CMPLX ( double re, double im ) : Re ( re ), Im ( im )

Class::Class ( ListaParametrów ) : PełnaListaInicjacyjna { …. }

{ }

gdzie dla wszystkich nietablicowych pól, których nie zawiera

albo

ListaInicjacyjna , dołą czone zostaną inicjatory bezparametrowe.

CMPLX::CMPLX ( double re, double im ) : Im ( im )

Pola tablicowe mogą być inicjowane tylko w treś ci konstruktora.

{ Re = re; }

// nieładne

i t.p.

Tomasz Marks - Wydział MiNI PW

-15-

Tomasz Marks - Wydział MiNI PW

-16-

PhVectorA – implementacje [4]

Tworzenie / niszczenie obiektów

PhVectorA::PhVectorA ( const PhVectorA& arg ) : W ( arg.W )

{

// składowa W juŜ istnieje zainicjowana

Etapy tworzenia obiektu:

// wywołaniem konstruktora Vector ( arg.W )

1. Przydział pamię ci dla niestatycznych pól obiektu.

strncpy ( Unit, arg.Unit, U_LEN );

2. Wykonanie inicjalizacji w oparciu o pełną listę inicjacyjną .

// i nic więcej nie trzeba robić !!!

3. Wykonanie treś ci konstruktora.

}

Ale UWAGA: Niemal dokładnie to samo zrobi predefiniowany

Etapy niszczenia obiektu:

konstruktor kopiują cy, realizują cy kopiowanie płytkie: dla pól obiektowych zostaną uŜ yte odpowiednie konstruktory kopiują ce,

1. Wykonanie treś ci destruktora.

a dla pozostałych (nieobiektowych i tablicowych) wykonane bę dzie

2. Wykonanie treś ci destruktorów pól składowych.

proste kopiowanie zawartoś ci pamię ci.

3. Zwolnienie pamię ci przydzielonej dla niestatycznych pól obiektu.

WNIOSEK: Definicję (i deklarację ) tego konstruktora moŜ na (naleŜ y)

w klasie PhVectorA pominąć .

Tomasz Marks - Wydział MiNI PW

-17-

Tomasz Marks - Wydział MiNI PW

-18-

PhVectorA – implementacje [5]

PhVectorA – implementacje [6]

PhVectorA& PhVectorA::operator = ( const PhVectorA& rhs ) PhVectorA::~PhVectorA ( )

{

{

W = rhs.W; // operacja w klasie Vector

// nic nie trzeba robić !!!

strcpy ( Unit, rhs.Unit ); // nie trzeba kontrolować długości tekstu,

}

// bo zakładamy poprawność obu obiektów

return *this;

UWAGA 1.: JeŜ eli destruktor został zadeklarowany, to musimy

}

zdefiniować jego implementację .

Ale UWAGA: Niemal dokładnie to samo zrobi predefiniowany

UWAGA 2.: Dokładnie to samo nic zrobiłby destruktor predefiniowany.

operator przypisania, realizują cy kopiowanie płytkie: dla pól obiektowych zostaną uŜ yte odpowiednie operatory przypisania,

WNIOSEK: Definicję (i deklarację ) destruktora moŜ na (naleŜ y)

a dla pozostałych (nieobiektowych i tablicowych) wykonane bę dzie

w klasie PhVectorA pominąć .

proste kopiowanie zawartoś ci pamię ci.

WNIOSEK: Definicję (i deklarację ) tego operatora moŜ na (naleŜ y)

w klasie PhVectorA pominąć .

Tomasz Marks - Wydział MiNI PW

-19-

Tomasz Marks - Wydział MiNI PW

-20-

PhVectorA – implementacje [7]

PhVectorA – uŜycie [1]

// phva_prog.cpp

Implementacje strumieniowych operatorów WE/WY:

#include "phvectora.h"

double forA [ ] = { 1., 2., 3., };

istream& operator >> ( istream& inp, PhVectorA& vec ) double forB [ ] = { 4., 5., 6., };

{

int main ( )

……………

{

return inp;

PhVectorA A ( 3, forA, "m/s" ), B ( 3, forB, "m/s" ), C;

}

double a, b; int i, j;

char txt [ 20 ];

ostream& operator << ( ostream& out, const PhVectorA& vec ) strcpy ( txt, A.getUnit ( ) ); // o.k.

{

i = B.getSize ( ); // BŁĄD

……………

j = B.W.getSize ( ); // o.k.

a = A [ 2 ]; // BŁĄD

return out;

b = A.W [ 2 ]; // o.k.

}

C.setUnit ( "m/s2" ); // o.k.

C = A + B; // BŁĄD

pozostawiam jako ć wiczenie.

C.W = A.W + B.W; // o.k. ale co z jednostkami w C ???

C.setUnit ( A.getUnit ( ) ); // o.k.

Tomasz Marks - Wydział MiNI PW

-21-

Tomasz Marks - Wydział MiNI PW

-22-

PhVectorA – uŜycie [2]

Klasa z polem składowym typu Vector [3]

// phvectora.h

………………………………….

WNIOSEK:

class PhVectorA

{

public:

ś eby operacje takie jak

Vector W;

private:

getSize( )

(pobranie rozmiaru),

char Unit [ U_LEN ];

public:

[ ]

(indeksowanie),

PhVectorA ( int = 0, double* = 0, char* = "" );

+

(dodawanie),

void setUnit ( const char* );

const char* getUnit ( ) const;

były dostę pne dla obiektów klasy PhVectorA , bez jawnej kwalifikacji int getSize ( ) const;

nazwą pola klasy Vector , to musimy je przeciąŜ yć w klasie PhVectorA .

double& operator [ ] ( int );

friend PhVectorA operator + (const PhVectorA&, const PhVectorA& );

………………………………….

};

Tomasz Marks - Wydział MiNI PW

-23-

Tomasz Marks - Wydział MiNI PW

-24-

PhVectorA – implementacje [8]

int PhVectorA::getSize ( ) const

{ return W.getSize ( ); }

double& PhVectorA:: operator [ ] ( int i )

{ return W[ i ]; }

// funkcja zaprzyjaźniona

Koniec wykładu 6.

PhVectorA operator+ ( const PhVectorA& a, const PhVectorA& b )

{

PhVectorA c;

c.W = a.W + b.W; // operacja w klasie Vector

c.setUnit( a.Unit );

return c;

}

Tomasz Marks - Wydział MiNI PW

-25-

Tomasz Marks - Wydział MiNI PW

-26-