Tomasz Marks - Wydział MiNI PW
-1-
Programowanie
(j
ę
zyk C++)
Wykład 6.
Tomasz Marks - Wydział MiNI PW
-2-
Projekt klasy
Vector
c.d.
Tomasz Marks - Wydział MiNI PW
-3-
Projekt klasy Vector – u
ż
ycie [3]
int main ( )
{
Vector v1 ( 3, 20. ), v2 ( 5, 10. ), v3;
v3 = v1 + v2;
cout << v1 << v2 << v3;
// 20 20 20
// 10 10 10 10 10
// 30 30 30 10 10
v3 = v1 + 2;
cout << v3;
// 20 20 20
v3 = v1 + 5;
cout << v3;
// 20 20 20 0 0
v3 = 10.2 + v1;
cout << v3;
// 20 20 20 0 0 0 0 0 0 0
Tomasz Marks - Wydział MiNI PW
-4-
Projekt klasy Vector – u
ż
ycie [4]
int main ( )
{
Vector v1 ( 3, 20. ), v2 ( 5, 10. ), v3;
v3 = v1 + v2;
// v3 = operator+ ( v1, v2 );
cout << v1 << v2 << v3;
// 20 20 20
// 10 10 10 10 10
// 30 30 30 10 10
v3 = v1 + 2;
// v3 = operator+ ( v1, Vector(2) );
cout << v3;
// 20 20 20
v3 = v1 + 5;
// v3 = operator+ ( v1, Vector(5) );
cout << v3;
// 20 20 20 0 0
v3 = 10.2 + v1;
// v3 = operator+ ( Vector( int(10.2) ), v1 );
cout << v3;
// 20 20 20 0 0 0 0 0 0 0
Tomasz Marks - Wydział MiNI PW
-5-
Projekt klasy Vector – u
ż
ycie [5]
int main ( )
{
Vector v1 ( 3, 20. ), v2 ( 5, 10. ), v3;
double ilskal;
ilskal = v1 * v2;
// ilskal = operator* ( v1, v2 );
cout << v1 << v2 << ilskal;
// 20 20 20
// 10 10 10 10 10
// 600
v3 = 2 * v1;
// v3 = operator* ( double(2), v1 );
cout << v3;
// 40 40 40
ilskal = v1 * 5.2;
// ilskal = operator*(v1, Vector(int(5.2)));
cout << ilskal;
// 0
……………………………
Tomasz Marks - Wydział MiNI PW
-6-
UWAGA:
Aby si
ę
ustrzec przed tego typu niespodziankami, nale
ż
y zadeklarowa
ć
konstruktor, który mo
ż
na wywoła
ć
z jednym argumentem typu int, jako
explicit
Vector ( int size, double val=0 );
co zabrania u
ż
ycia konstruktora dla niejawnej konwersji parametrów,
i przewidzie
ć
funkcje dla innych układów parametrów, oprócz:
friend Vector operator + ( const Vector& a, const Vector& b );
friend Vector operator * ( double k, const Vector& a );
friend double operator * ( const Vector& a, const Vector& b );
równie
ż
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
-7-
Nowy
problem projektowy
Tomasz Marks - Wydział MiNI PW
-8-
Problem projektowy
DANE WEJ
Ś
CIOWE:
Dysponujemy dobrze zdefiniowan
ą
i przetestowan
ą
klas
ą
Vector,
która faktycznie pozwala na operowanie dynamicznie alokowanymi
tablicami danych liczbowych.
ZADANIE:
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 PhVectorX
Prze
ś
ledzimy dwa sposoby podej
ś
cia do tego problemu definiuj
ą
c
dwie klasy:
PhVectorA
i PhVectorB.
Tomasz Marks - Wydział MiNI PW
-9-
Klasa
z polem składowym
typu Vector
Tomasz Marks - Wydział MiNI PW
-10-
Klasa z polem składowym typu Vector [1]
// phvectora.h
#include "vector.h"
#define U_LEN 10
class PhVectorA
{
public:
Vector W;
private:
char Unit [ U_LEN ];
public:
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
-11-
Klasa z polem składowym typu Vector [2]
// phvectora.h
#include "vector.h"
#define U_LEN 10
class PhVectorA
{
public:
Vector W;
private:
char Unit [ U_LEN ];
public:
PhVectorA ( int = 0, double* = 0,
const
char* = "" );
PhVectorA ( const PhVectorA& );
~PhVectorA ( );
PhVectorA& operator = ( const PhVectorA& );
void setUnit (
const
char* );
const
char* getUnit ( ) const;
friend istream& operator >> ( istream&, PhVectorA& );
friend ostream& operator << ( ostream&, const PhVectorA& );
};
Tomasz Marks - Wydział MiNI PW
-12-
PhVectorA – implementacje [1]
// phvectora.cpp
#include <cstring>
// ew. <string.h> jak w j
ę
z. C
// niektóre kompilatory pozwalaj
ą
pomija
ć
// pliki nagłówkowe 'odziedziczone' z C
#include "phvectora.h"
const char* PhVectorA::getUnit ( ) const
{ return Unit; }
void PhVectorA::setUnit ( const char* str )
{ strncpy ( Unit, str, U_LEN ); }
………………………………………………………...
…………………………………………………………
Tomasz Marks - Wydział MiNI PW
-13-
PhVectorA – implementacje [2]
PhVectorA::PhVectorA ( int s, double tab[ ], char* u )
{
// składowa W ju
ż
istnieje zainicjowana
// wywołaniem konstruktora Vector ( )
strncpy ( Unit, u, U_LEN );
// jak "przewymiarowa
ć
" składow
ą
W, by miała rozmiar s
// i była zapełniona warto
ś
ciami z tablicy tab ???
………………………………………………………...
…………………………………………………………
Tomasz Marks - Wydział MiNI PW
-14-
PhVectorA – implementacje [3]
PhVectorA::PhVectorA ( int s, double tab[ ], char* u ) : W ( s, tab )
{
// składowa W ju
ż
istnieje zainicjowana
// wywołaniem konstruktora Vector ( s, tab )
strncpy ( Unit, u, U_LEN );
// i nic wi
ę
cej nie trzeba robi
ć
!!!
}
Tomasz Marks - Wydział MiNI PW
-15-
Lista inicjacyjna konstruktora [1]
Definicja konstruktora postaci
Class::Class ( ListaParametrów ) : ListaInicjacyjna { …. }
gdzie ListaParametrów i ListaInicjacyjna mog
ą
by
ć
puste,
jest równowa
ż
na definicji
Class::Class ( ListaParametrów ) : PełnaListaInicjacyjna { …. }
gdzie dla wszystkich nietablicowych pól, których nie zawiera
ListaInicjacyjna, doł
ą
czone zostan
ą
inicjatory bezparametrowe.
Pola tablicowe mog
ą
by
ć
inicjowane tylko w tre
ś
ci konstruktora.
Tomasz Marks - Wydział MiNI PW
-16-
Lista inicjacyjna konstruktora [2]
U
ż
ycie listy inicjacyjnej nie ogranicza si
ę
do inicjowania składowych
obiektowych, n.p. zamiast
CMPLX::CMPLX ( double re, double im )
{ Re = re; Im = im; }
mo
ż
emy napisa
ć
CMPLX::CMPLX ( double re, double im ) : Re ( re ), Im ( im )
{ }
albo
CMPLX::CMPLX ( double re, double im ) : Im ( im )
{ Re = re; }
// nieładne
i t.p.
Tomasz Marks - Wydział MiNI PW
-17-
PhVectorA – implementacje [4]
PhVectorA::PhVectorA ( const PhVectorA& arg )
: W ( arg.W )
{
// składowa W ju
ż
istnieje zainicjowana
// wywołaniem konstruktora
Vector ( arg.W )
strncpy ( Unit, arg.Unit, U_LEN );
// i nic wi
ę
cej nie trzeba robi
ć
!!!
}
Ale
UWAGA:
Niemal dokładnie to samo zrobi predefiniowany
konstruktor kopiuj
ą
cy, realizuj
ą
cy kopiowanie płytkie: dla pól
obiektowych zostan
ą
u
ż
yte odpowiednie konstruktory kopiuj
ą
ce,
a dla pozostałych (nieobiektowych i tablicowych) wykonane b
ę
dzie
proste kopiowanie zawarto
ś
ci pami
ę
ci.
WNIOSEK:
Definicj
ę
(i deklaracj
ę
) tego konstruktora mo
ż
na (nale
ż
y)
w klasie PhVectorA pomin
ąć
.
Tomasz Marks - Wydział MiNI PW
-18-
Tworzenie / niszczenie obiektów
Etapy tworzenia obiektu:
1. Przydział pami
ę
ci dla niestatycznych pól obiektu.
2. Wykonanie inicjalizacji w oparciu o pełn
ą
list
ę
inicjacyjn
ą
.
3. Wykonanie tre
ś
ci
konstruktor
a.
Etapy niszczenia obiektu:
1. Wykonanie tre
ś
ci
destruktor
a.
2. Wykonanie tre
ś
ci destruktorów pól składowych.
3. Zwolnienie pami
ę
ci przydzielonej dla niestatycznych pól obiektu.
Tomasz Marks - Wydział MiNI PW
-19-
PhVectorA – implementacje [5]
PhVectorA::~PhVectorA ( )
{
// nic nie trzeba robi
ć
!!!
}
UWAGA 1.:
Je
ż
eli destruktor został zadeklarowany, to musimy
zdefiniowa
ć
jego implementacj
ę
.
UWAGA 2.:
Dokładnie to samo nic zrobiłby destruktor predefiniowany.
WNIOSEK:
Definicj
ę
(i deklaracj
ę
) destruktora mo
ż
na (nale
ż
y)
w klasie PhVectorA pomin
ąć
.
Tomasz Marks - Wydział MiNI PW
-20-
PhVectorA – implementacje [6]
PhVectorA& PhVectorA::operator = ( const PhVectorA& rhs )
{
W = rhs.W;
// operacja w klasie Vector
strcpy ( Unit, rhs.Unit );
// nie trzeba kontrolowa
ć
długo
ś
ci tekstu,
// bo zakładamy poprawno
ść
obu obiektów
return *this;
}
Ale
UWAGA:
Niemal dokładnie to samo zrobi predefiniowany
operator przypisania, realizuj
ą
cy kopiowanie płytkie: dla pól
obiektowych zostan
ą
u
ż
yte odpowiednie operatory przypisania,
a dla pozostałych (nieobiektowych i tablicowych) wykonane b
ę
dzie
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
-21-
PhVectorA – implementacje [7]
Implementacje strumieniowych operatorów WE/WY:
istream& operator >> ( istream& inp, PhVectorA& vec )
{
……………
return inp;
}
ostream& operator << ( ostream& out, const PhVectorA& vec )
{
……………
return out;
}
pozostawiam jako
ć
wiczenie.
Tomasz Marks - Wydział MiNI PW
-22-
PhVectorA – u
ż
ycie [1]
// phva_prog.cpp
#include "phvectora.h"
double forA [ ] = { 1., 2., 3., };
double forB [ ] = { 4., 5., 6., };
int main ( )
{
PhVectorA A ( 3, forA, "m/s" ), B ( 3, forB, "m/s" ), C;
double a, b; int i, j;
char txt [ 20 ];
strcpy ( txt, A.getUnit ( ) );
// o.k.
i = B.getSize ( );
//
BŁ
Ą
D
j = B.W.getSize ( );
// o.k.
a = A [ 2 ];
//
BŁ
Ą
D
b = A.W [ 2 ];
// o.k.
C.setUnit ( "m/s2" );
// o.k.
C = A + B;
//
BŁ
Ą
D
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
-23-
PhVectorA – u
ż
ycie [2]
WNIOSEK:
ś
eby operacje takie jak
getSize( )
(pobranie rozmiaru),
[ ]
(indeksowanie),
+
(dodawanie),
były dost
ę
pne dla obiektów klasy PhVectorA, bez jawnej kwalifikacji
nazw
ą
pola klasy Vector, to musimy je przeci
ąż
y
ć
w klasie PhVectorA.
Tomasz Marks - Wydział MiNI PW
-24-
Klasa z polem składowym typu Vector [3]
// phvectora.h
………………………………….
class PhVectorA
{
public:
Vector W;
private:
char Unit [ U_LEN ];
public:
PhVectorA ( int = 0, double* = 0, char* = "" );
void setUnit ( const char* );
const char* getUnit ( ) const;
int getSize ( ) const;
double& operator [ ] ( int );
friend PhVectorA operator + (const PhVectorA&, const PhVectorA& );
………………………………….
};
Tomasz Marks - Wydział MiNI PW
-25-
PhVectorA – implementacje [8]
int PhVectorA::getSize ( ) const
{ return W.getSize ( ); }
double& PhVectorA:: operator [ ] ( int i )
{ return W[ i ]; }
// funkcja zaprzyja
ź
niona
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
-26-
Koniec wykładu 6.