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 [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-
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 – 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-
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-