Dziedziczenie
Część trzecia
Roman Simiński
roman.siminski@us.edu.pl
www.us.edu.pl/~siminski
Autor KontaktWprowadzenie do programowanie
Wprowadzenie do programowanie
obiektowego w języku C++
obiektowego w języku C++
Co było przyczyną powstania koncepcji dzedziczenia?
Co było przyczyną powstania koncepcji dzedziczenia?
Ponowne wykorzystanie elementów oprogramowania
W trakcie projektowania i realizacji systemów informatycznych wielokrotnie
powtarzają się jednakowe lub podobne elementy oprogramowania.
Powtarzalność taką można obserwować zarówno etapie analizy, projektowania i
programowania.
Na etapie analizy są to zwykle obiekty dziedziny problemu, na etapie projektowania
i programowania zarówno obiekty dziedziny problemu jak i obiekty
implementacyjne.
Ponowne wykorzystanie (ang. reuse) pozwala:
na zwiększenie wydajności procesu programowania,
poprawia jakość i niezawodność kodu,
Co było przyczyną powstania koncepcji dzedziczenia?
Co było przyczyną powstania koncepcji dzedziczenia?
Ponowne wykorzystanie kodu w programowaniu obiektowym
Podejście obiektowe eksponuje rolę obiektu – jest on abstrakcją pewnego
konkretnego bytu ze świata rzeczywistego, reprezentujący rzecz (obiekt fizyczny)
lub pojęcie (obiekt konceptualny).
W programowaniu obiektowym ponowne wykorzystanie kodu polega na
wykorzystaniu obiektów tej samej, raz zdefiniowanej klasy w różnych projektach.
Marka
Model
Rok produkcji
Nr rejestracyjny
Kolor nadwozia
Nr silnika
. . .
C
ec
h
y
Podaj średnie spalanie
Podaj przebieg
. . .
A
kc
je
Klasa: Auto
Co było przyczyną powstania koncepcji dzedziczenia?
Co było przyczyną powstania koncepcji dzedziczenia?
Niestety
W obrębie obiektów dziedziny problemu powtarzają się obiekty podobne lecz
bardzo rzadko identyczne.
Autokomis
Auto
Stacja diagnostycznaAuto
SerwisAuto
AutosalonAuto
SprzedażFaktura
Biuro rachunkoweFaktura
WindykacjaFaktura
Finanse-KsięgowośćFaktura
Co było przyczyną powstania koncepcji dzedziczenia?
Co było przyczyną powstania koncepcji dzedziczenia?
Niestety
W obrębie obiektów implementacyjnych powtarzalność obiektów identycznych jest
znacznie częstsza, co jednak nie jest regułą.
Okno aplikacji
Belka narzedziowa
Okno dialogowe
Co było przyczyną powstania koncepcji dzedziczenia?
Co było przyczyną powstania koncepcji dzedziczenia?
Ponowne wykorzystanie kodu – problemy
Powtarzalność nieidentycznych obiektów powoduje to, że musimy modyfikować
istniejący kod, dostosowując go do specyfiki projektu.
Modyfikacje potrzebne z punktu widzenia jednego systemu mogą być nieużyteczne
lub nieakceptowalne z punktu widzenia innego systemu.
Modyfikacje dostosowujące kod do specyfiki systemu zmuszają do utrzymywania
różnych wersji tego samego kodu.
Autokomis
Auto
Stacja diagnostycznaAuto
SerwisAuto
Modyfikacje Modyfikacje Modyfikacje AutosalonAuto
Konieczność wprowadzenia w kodzie zmian o charakterze podstawowym, może
spowodować konieczność zmodyfikowania wielu różnych jego wersji. Jest to
uciążliwe, nieproduktywne i może być przyczyną błędów.
Koncepcja dziedziczenia
Koncepcja dziedziczenia
Ponowne wykorzystanie kodu z wykorzystaniem dziedziczenia
Dziedziczenie polega na budowaniu nowych klas,
zwanych klasami potomnymi, na podstawie klas już
istniejących, zwanych klasami bazowymi.
Każda klasa pochodna dziedziczy wszystkie
właściwości klasy bazowej, rozszerzając ją o nowe
atrybuty (pola) i usługi (metody).
W wyniku dziedziczenia klasa pochodna otrzymuje wszystkie pola i metody klasy
bazowej. 100% składowych klasy bazowej występuje w klasie pochodnej.
AutoWKomisie
cena
dataPrzyjecia
wlasciciel
. . .
Auto
marka
model
rokProd
nrRej
. . .
Do są nowe elementy, dodane w klasie AutoWKomisie
To już mamy, przejmujemy z klasy Auto
Koncepcja dziedziczenia
Koncepcja dziedziczenia
Klasa Auto jako klasa bazowa klasy AutoWKomisie
Klasa bazowa
Auto
marka
model
rokProd
nrRej
. . .
AutoWKomisie
cena
dataPrzyjecia
wlasciciel
. . .
Klasa potomna
Dziedziczenie
Koncepcja dziedziczenia
Koncepcja dziedziczenia
Klasa Auto jako klasa bazowa klasy AutoWStacjiDiagn
Klasa bazowa
Auto
marka
model
rokProd
nrRej
. . .
AutoWStacjiDiagn
dataPrzegladu
nastepnyPrzeglad
diagnosta
. . .
Klasa potomna
Dziedziczenie
Koncepcja dziedziczenia
Koncepcja dziedziczenia
Klasa Auto jako klasa bazowa klasy AutoWSerwisie
Klasa bazowa
Auto
marka
model
rokProd
nrRej
. . .
AutoWSerwisie
przebieg
numerKomputerowy
. . .
Klasa potomna
Dziedziczenie
Koncepcja dziedziczenia
Koncepcja dziedziczenia
Klasa bazowa i klasy potomne tworzą hierarchię klas
Auto
marka
model
rokProd
nrRej
. . .
AutoWSerwisie
przebieg
numerKomputerowy
. . .
AutoWStacjiDiagn
dataPrzegladu
nastepnyPrzeglad
diagnosta
. . .
AutoWKomisie
cena
dataPrzyjecia
wlasciciel
. . .
Koncepcja dziedziczenia
Koncepcja dziedziczenia
Klasa bazowa jako klasa ogólna
Klasa bazowa (nadklasa) reprezentuje pojęcie bardziej ogólne, znajdujące się na
wyższym poziomie abstrakcji.
Auto marka model rokProd nrRej . . . AutoWSerwisie przebieg numerKomputerowy . . . AutoWStacjiDiagn dataPrzegladu nastepnyPrzeglad diagnosta . . . AutoWKomisie cena dataPrzyjecia wlasciciel . . .
Koncepcja dziedziczenia
Koncepcja dziedziczenia
Klasy pochodne jako klasy specjalizowane
Auto marka model rokProd nrRej . . . AutoWSerwisie przebieg numerKomputerowy . . . AutoWStacjiDiagn dataPrzegladu nastepnyPrzeglad diagnosta . . . AutoWKomisie cena dataPrzyjecia wlasciciel . . .
Klasy pochodne (podklasay) reprezentuje pojęcie bardziej szczegółowe,
Koncepcja dziedziczenia a generalizacja-specjalizacja
Koncepcja dziedziczenia a generalizacja-specjalizacja
Dziedziczenie jako środek realizacji modeli generalizacja-specjalizacja
Pojęcie specjalizacja-generalizacja umożliwia organizowanie klas w struktury
hierarchiczne, w których nadklasa reprezentuje pojęcia bardziej ogólne, a podklasa
pojęcia specjalizowane.
Klasa ogólna
Auto
marka
model
rokProd
nrRej
. . .
AutoWKomisie
cena
dataPrzyjecia
wlasciciel
. . .
Klasa specjalizowana
Generalizacja-specjalizacja
Ogólno ć i poziom abstrakcji
ś
Koncepcja dziedziczenia a generalizacja-specjalizacja
Koncepcja dziedziczenia a generalizacja-specjalizacja
Jak zweryfikować poprawność wykorzystania dziedziczenia?
Reguła is-a (ang. is a kind of) pozwala na sprawdzenie czy zachodzi związek dziedziczenia
(specjalizacji–generalizacji) pomiędzy klasami.
Realizowane jest to poprzez sprawdzenie poprawności zdania:
Czy klasa pochodna jest pewnego rodzaju (is-a) klasą bazową?
precyzyjniej
Czy obiekt klasy pochodnej jest pewnego rodzaju (is-a) obiektem klasy bazowej?
Auto
marka
model
rokProd
nrRej
. . .
AutoWKomisie
cena
dataPrzyjecia
wlasciciel
. . .
Czy AutoWKomisie jest pewnego
Koncepcja dziedziczenia a generalizacja-specjalizacja
Koncepcja dziedziczenia a generalizacja-specjalizacja
Przykład weryfikacji poprawności dziedziczenia
Zadajemy dwa pytania:
czy obiekt klasy A jest obiektem klasy B? (A is-a B?)
czy obiekt klasy B jest obiektem klasy A? (B is-a A?)
Możliwe odpowiedzi:
zawsze,
nigdy
czasami.
Interpretacja:
dwie odpowiedzi nigdy: brak związku specjalizacja-generalizacja,
dwie odpowiedzi zawsze: obiekty A i B są synonimiczne (np. dwie różne nazwy dla
tej samej klasy)
jeżeli: A is-a B = zawsze oraz B is_a A = czasami wtedy A jest specjalizacją B (A
is-a B).
Koncepcja dziedziczenia a generalizacja-specjalizacja
Koncepcja dziedziczenia a generalizacja-specjalizacja
Przykład weryfikacji poprawności dziedziczenia
Czy klasa
AutoWKomisie
jest klasą pochodną klasy
Auto
:
czy obiekt klasy
AutoWKomisie
jest obiektem klasy
Auto
?
←
Zawsze
czy obiekt klasy
Auto
jest obiektem klasy
AutoWKomisie
?
←
Czasami
A jak ten test przejdą standardowe przykłady dziedziczenia z
popularnych książek o programowaniu obiektowym?
Koncepcja dziedziczenia a generalizacja-specjalizacja
Koncepcja dziedziczenia a generalizacja-specjalizacja
Przykład weryfikacji poprawności dziedziczenia
(x, y)
(x, y)
r
(x, y)
w
h
?
Point
x
y
. . .
Circle
r
. . .
Rectangle
w
h
. . .
?
Punkt
Okr g
ą
Prostok t
ą
Koncepcja dziedziczenia a generalizacja-specjalizacja
Koncepcja dziedziczenia a generalizacja-specjalizacja
Przykład weryfikacji poprawności dziedziczenia
Czy klasa
Circle
jest klasą pochodną klasy
Point
:
czy obiekt klasy
Circle
jest pewnego rodzaju obiektem klasy
Point
?
←
?
czy obiekt klasy
Point
jest pewnego rodzaju obiektem klasy
Circle
?
←
?
(x, y)
(x, y)
r
(x, y)
w
h
Punkt
Okr g
ą
Prostok t
ą
Czy klasa
Rectangle
jest klasą pochodną klasy
Point
:
czy obiekt klasy
Prostokat
jest pewnego rodzaju obiektem klasy
Point
?
←
?
Koncepcja dziedziczenia a związki całość-część
Koncepcja dziedziczenia a związki całość-część
Jeżeli nie dziedziczenie to co?
Często obiekty łączy relacja is_part czyli jest częścią (ang. is a part of). Relacja ta
określana jest pojęciem całość-część.
Przy związkach całość-część zadajemy pytania:
czy obiekt klasy
A
jest częścią obiektu klasy
B
?
czy obiekt klasy
B
zawiera w sobie obiekt klasy
A
?
Point
x
y
. . .
Circle
r
. . .
Rectangle
w
h
. . .
Klasa obiektu-całości
Klasa obiektu składowego
Definiowanie klas pochodnych
Definiowanie klas pochodnych
Anatomia dziedziczenia w C++ na przykładzie
Punkt
(x, y, z)
x
y
z
(x, y)
x
y
Punkt3D
Point
x
y
. . .
Point3D
z
. . .
Czy Punkt3D jest pewnego
Definiowanie klas pochodnych
Definiowanie klas pochodnych
Anatomia dziedziczenia w C++ na przykładzie
#include <iostream> using namespace std; // . . . int main() { Point p1( 10, 12 ); Point3D p2( 2, 5, 4 );
cout << endl << "Punkt 2D ma wspolrzedne" << endl; cout << "x = " << p1.getX() << endl;
cout << "y = " << p1.getY() << endl;
cout << endl << "Punkt 3D ma wspolrzedne" << endl; cout << "x = " << p2.getX() << endl;
cout << "y = " << p2.getY() << endl; cout << "z = " << p2.getZ() << endl; return EXIT_SUCCESS;
}
Definiowanie klas pochodnych
Definiowanie klas pochodnych
Anatomia dziedziczenia w C++ na przykładzie
class Point {
public :
// Konstruktory
Point() : x( 0 ), y( 0 ) { }
Point( int x, int y ) : x( x ), y( y ) { }
// Modyfikator i akcesor dla pola x
void setX( int x ) { Point::x = x; } int getX() const { return x; }
// Modyfikator i akcesor dla pola y void setY( int y ) { Point::y = y; } int getY() const { return y; }
private: int x, y; };
Definiowanie klas pochodnych
Definiowanie klas pochodnych
Anatomia dziedziczenia w C++ na przykładzie
class Point3D : public Point
{
public :
// Konstruktory
Point3D() : Point(), z( 0 ) { }
Point3D( int x, int y, int z ) : Point( x, y ), z( z ) { }
// Modyfikator i akcesor dla pola z
void setZ( int z ) { Point3D::z = z; } int getZ() const { return z; }
private: int z; };
Definiowanie klas pochodnych
Definiowanie klas pochodnych
Anatomia dziedziczenia w C++ na przykładzie
class Point3D : public Point
{
public :
// Konstruktory
Point3D() : Point(), z( 0 ) { }
Point3D( int x, int y, int z ) : Point( x, y ), z( z ) { }
// Modyfikator i akcesor dla pola z
void setZ( int z ) { Point3D::z = z; } int getZ() const { return z; }
private: int z; };
Dziedziczenie w trybie publicznym zachowuje
widoczność pól określoną w klasie bazowej.
Konstruktor klasy pochodnej aktywuje konstruktor klasy bazowej
umieszczony na liście inicjalizacyjnej, odbywa się to
Definiowanie klas pochodnych
Definiowanie klas pochodnych
Anatomia dziedziczenia w C++ na przykładzie
class Point3D : public Point
{
public :
// Konstruktory
Point3D() : Point(), z( 0 ) { }
Point3D( int x, int y, int z ) : Point( x, y ), z( z ) { }
// Modyfikator i akcesor dla pola z
void setZ( int z ) { Point3D::z = z; } int getZ() const { return z; }
private: int z; };
W klasie pochodnej definiujemy metody do
obsługi nowych pól, obsługę pól odziedziczonych
realizujemy z wykorzystaniem metod odziedziczonych.
Używamy konstruktorów klasy bazowej do zainicjowania
pól odziedziczonych, nowe pola inicjują własne konstruktory.
Definiowanie klas pochodnych
Definiowanie klas pochodnych
Anatomia dziedziczenia w C++ na przykładzie
Punkt
(x, y)
x
y
Piksel
Point
x
y
. . .
Pixel
color
. . .
Czy Piksel jest pewnego
rodzaju Punktem?
x
Definiowanie klas pochodnych
Definiowanie klas pochodnych
Anatomia dziedziczenia w C++ na przykładzie
class Pixel : public Point
{
public :
// Konstruktory
Pixel() : Point(), color( 0 ) { }
Pixel( int x, int y, int color ) : Point( x, y ), color( color ) { }
// Modyfikator i akcesor dla pola color
void setColor( int color ) { Pixel::color = color; } int getColor() const { return color; }
// Realizator
void put() const {
// Funkcja wy wietl. piksela z odpowiedniej bibl. graficznej, np.:ś putpixel( getX(), getY(), color );
}
private:
int color; };
Definiowanie klas pochodnych
Definiowanie klas pochodnych
Anatomia dziedziczenia w C++ na przykładzie
Piksel
x
y
PikselEkranowy
x
y
Ograniczenia
minx, miny,
maxx, maxy.
ScrPixel
minx, miny
maxx, maxy
. . .
Czy PikselEkranowy jest pewnego
rodzaju Pikselem?
Pixel
color
Definiowanie klas pochodnych
Definiowanie klas pochodnych
Anatomia dziedziczenia w C++ na przykładzie
class ScrPixel : public Pixel
{
public :
ScrPixel() : Pixel() { }
ScrPixel( int x, int y, int color ) : Pixel( x, y, color ) { } void setX( int x )
{
Point::setX( ( x >= minx && x <= maxx ) ? x : 0 ); }
void setY( int y ) {
Point::setY( ( y >= miny && y <= maxy ) ? y : 0 ); }
static int minx, miny, maxx, maxy;
};
int ScrPixel::minx = 0; int ScrPixel::miny = 0; int ScrPixel::maxx = 799; int ScrPixel::maxy = 599;
Definiowanie klas pochodnych
Definiowanie klas pochodnych
Ma marginesie — pola statyczne
Pola statyczne dla danej klasy występują tylko raz, są współdzielone przez wszystkie
obiekty tej klasy. Istnieją nawet wtedy, gdy nie został utworzony żaden obiekt klasy.
Pola statyczne muszą być zdefiniowane poza klasą, nadaje się im tedy wartość
początkową.
int ScrPixel::minx = 0; int ScrPixel::miny = 0; int ScrPixel::maxx = 799; int ScrPixel::maxy = 599;
Do pól statycznych klasy można odwoływać się bez obiektu:
ScrPixel::maxx = screen.getMaxX();ScrPixel::maxy = screen.getMaxY();
Pola statyczne stanowią wspólną, współdzieloną pamięć wszystkich obiektów danej
klasy.
Definiowanie klas pochodnych
Definiowanie klas pochodnych
Redefinicja metody (funkcji składowej) w klasie pochodnej
class Point {
. . .
void setX( int x ) { Point::x = x; }
};
class ScrPixel : public Pixel {
. . .
void setX( int x )
{
Point::setX( ( x >= minx && x <= maxx ) ? x : 0 ); }
};
W klasie pochodnej można zmienić sposób działania metody odziedziczonej poprzez
jej redefinicję.
Do metody odziedziczonej można dalej odwoływać się stosując prefiks w postaci
nazwa_klasy_bazowej::
.
Redefinicję metody w klasie pochodnej stosujemy wtedy, gdy nie odpowiada nam
działanie metody odziedziczonej. Można napisać własną implementację metody,
opcjonalnie posługując się również metodą odziedziczoną.
Definiowanie klas pochodnych
Definiowanie klas pochodnych
Składowe chronione
class Pixel : public Point {
public : . . .
void put() const {
putpixel( getX(), getY(), color ); }
. . . };
Składowe zadeklarowane jako protected są dostępne dla obiektów wszystkich klas
pochodnych (tak jak składowe public).
Składowe zadeklarowane jako protected są niedostępne dla obiektów innych,
niezaprzyjaźnionych klas (tak jak składowe private).
Specyfikator protected działa jak private, z tym wyjątkiem, że obiekty klas
W klasie pochodnej nie ma bezpośredniego dostępu do pól prywatnych klasy bazowej.
Przewidując, że pewna klasa będzie wykorzystywana jako klasa bazowa, można
zadeklarować jej składowe (pola i metody) jako chronione — protected:
Definiowanie klas pochodnych
Definiowanie klas pochodnych
Składowe chronione
class Point { public : . . . protected: int x, y; };Deklaracja pól x i y jako chronionych:
class Pixel : public Point {
public : . . .
void put() const {
putpixel( x, y, color ); // Dozwolone bezpo rednie odwołanie do x i yś }
. . . };
. . . Point p;
Definiowanie klas pochodnych
Definiowanie klas pochodnych
Na marginesie — destruktory
Destruktor to funkcja wywoływana automatycznie przez kompilator bezpośrednio
przed momentem, w którym obiekt przestaje „żyć”.
Moment „śmierci” obiektu zależy od tego, w jaki sposób został on utworzony.
Obiekty statyczne giną po zakończeniu wykonania funkcji
main
, obiekty
automatyczne po wyjściu sterowania z bloku w którym zostały zdefiniowane, obiekty
dynamicze w momencie usunięcia ich z pamięci operatorem
delete
.
Destruktor to bezparametrowa funkcja, bez określonego rezultatu, o nazwie takiej, jak
nazwa klasy poprzedzona znakiem tyldy „~”.
class Point { public: . . . // Destruktor ~Point(); . . . class ScrPixel { public: . . . // Destruktor ~ScrPixel(); . . .Definiowanie klas pochodnych
Definiowanie klas pochodnych
Na marginesie — destruktory
class Point { public : // Konstruktory Point() : x( 0 ), y( 0 ) {cout << endl << "Point()" << endl; }
Point( int x, int y ) : x( x ), y( y ) {
cout << endl << "Point( " << x << ", " << y << " )" << endl; }
// Destruktor ~Point()
{
cout << endl << "~Point()" << endl; }
. . . };
Klasa
Pointze zmodyfikowanymi konstruktorami i destruktorem
class Point { public : // Konstruktory Point() : x( 0 ), y( 0 ) {
cout << endl << "Point()" << endl; }
Point( int x, int y ) : x( x ), y( y ) {
cout << endl << "Point( " << x << ", " << y << " )" << endl; }
// Destruktor ~Point()
{
cout << endl << "~Point()" << endl; }
. . . };
Definiowanie klas pochodnych
Definiowanie klas pochodnych
Na marginesie — destruktory
. . .
cout << endl << "Przed utworzeniem obiektu p klasy Point" << endl; {
Point p( 1, 10 );
cout << endl << "Punkt ma wspolrzedne" << endl; cout << "x = " << p.getX() << endl;
cout << "y = " << p.getY() << endl; }
cout << endl << "Po usunieciu obiektu p klasy Point" << endl; . . .
Aktywowanie konstruktora i destruktora dla obiektu klasy
Point
:
Obiekt zaczyna żyć, aktywowanie
konstruktora
Obiekt umiera, aktywowanie
destruktora
Definiowanie klas pochodnych
Definiowanie klas pochodnych
class Point3D : public Point {
public :
// Konstruktory
Point3D() : Point(), z( 0 ) {
cout << endl << "Point3D()" << endl; }
Point3D( int x, int y, int z ) : Point( x, y ), z( z ) {
cout<< endl << "Point3D( " << x << ", " << y << ", " << z << " )" << endl; }
// Destruktor ~Point3D() {
cout << endl << "~Point3D()" << endl; }
. . . };
Klasa
Point3Dze zmodyfikowanymi konstruktorami i destruktorem
Definiowanie klas pochodnych
Definiowanie klas pochodnych
Kolejność aktywowania konstruktorów i destruktorów a dziedziczenie
class Pixel : public Point {
public :
// Konstruktory
Pixel() : Point(), color( 0 ) {
cout << endl << "Pixel()" << endl; }
Pixel( int x, int y, int color ) : Point( x, y ), color( color ) {
cout<< endl<< "Pixel( "<< x << ", " << y << ", " << color << " )" << endl; }
// Destruktor ~Pixel()
{
cout << endl << "~Pixel()" << endl; }
. . . };
Definiowanie klas pochodnych
Definiowanie klas pochodnych
Kolejność aktywowania konstruktorów i destruktorów a dziedziczenie
class ScrPixel : public Pixel {
public :
// Konstruktory
ScrPixel() : Pixel() {
cout << endl << "ScrPixel()" << endl; }
ScrPixel( int x, int y, int color ) : Pixel( x, y, color ) {
cout<< endl<< "ScrPixel( "<< x << ", "<< y << ", "<< color << " )"<< endl; }
// Destruktor ~ScrPixel() {
cout << endl << "~ScrPixel()" << endl; }
. . . };
Definiowanie klas pochodnych
Definiowanie klas pochodnych
Kolejność aktywowania konstruktorów i destruktorów a dziedziczenie
. . .
cout << endl << "Przed utworzeniem obiektu p klasy Point3D" << endl; {
Point3D p( 2, 5, 4 );
cout << endl << "Punkt 3D ma wspolrzedne" << endl; cout << "x = " << p.getX() << endl;
cout << "y = " << p.getY() << endl; cout << "z = " << p.getZ() << endl; }
cout << endl << "Po usunieciu obiektu p klasy Point3d" << endl; . . .
Aktywowanie konstruktora i destruktora dla obiektu klasy
Point3D
:
Aktywowanie konstruktora klasy bazowej
Aktywowanie konstruktora własnego klasy
Aktywowanie destruktora własnego klasy
Aktywowanie destruktora klasy bazowej
Definiowanie klas pochodnych
Definiowanie klas pochodnych
Kolejność aktywowania konstruktorów i destruktorów a dziedziczenie
. . .
cout << endl << "Przed utworzeniem obiektu p klasy ScrPixel" << endl; {
ScrPixel p( 10, 5, 0 );
cout << endl << "Piksel ma wspolrzedne" << endl; cout << "x = " << p.getX() << endl;
cout << "y = " << p.getY() << endl; }
cout << endl << "Po usunieciu obiektu p klasy ScrPixel" << endl; . . .