cpp cwiczenia podstawowe 2 Kluc Nieznany

background image

©2006 Jerzy Kluczewski










PROGRAMOWANIE OBIEKTOWE



Ćwiczenia podstawowe Cz. II






Przestrzenie nazw

Obiekty

Klasy

Odwołania do składowych obiektu

Właściwości obiektów

Przeciążanie metod

Sposoby przekazywania argumentów

Dynamiczne obiekty

Konstruktory i destruktory

Konstruktor kopiujący

Składowe statyczne

Dziedziczenie i klasy potomne

Dostęp do składowych klasy

Modyfikatory i dziedziczenie

Przesłanianie składowych klasy

Prosta hierarchia klas






background image

2

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II.

______________________________________________________________________

______________________________________________________________________

©2006 Jerzy Kluczewski

// MojeSortowanie.h
//---------------------------------------------------------------------------
// definicja przestrzeni nazw
namespace sudoku
{
#define SIZE 10

// STRUKTURA przechowująca cyfrę i jej częstosc
typedef struct {
int cyfra;
int czestosc;
} TCzestosc;

// TABLICA przechowująca indeksy o największej liczbie wystąpień
// cyfr w tablicy liczba_cyfr - posortowane rosnąco
static TCzestosc Cyferki[SIZE];

//---------------------------------------------------------------------------
// zeruj częstosc cyfr w tablicy cyferki
void zeruj_czestosc_cyfr(void)
{
for (int i=0; i<SIZE; i++)
{
Cyferki[i].cyfra = i;
Cyferki[i].czestosc = 0;
}
}

I.

Przestrzenie nazw


Przykładowy program składa się z dwóch plików: MojeSortowanie.h (biblioteka
obsługująca przestrzeń nazw sudoku) oraz MojeSortowanie.cpp (plik źródłowy
programu korzystający ze zmiennych i funkcji należących do przestrzeni nazw sudoku)

W pliku nagłówkowym w przestrzeni nazw sudoku, zdefiniowano następujące
elementy:

stałą SIZE

strukturę TCzestosc

tablicę statyczną Cyferki[ROZMIAR_TABL]

funkcję zeruj_czestosc_cyfr

funkcję Cyferki_Sortuj


Oto plik nagłówkowy MojeSortowanie.h






























Plik MojeSortowanie.h.

background image

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II. 3
______________________________________________________________________

©2006 Jerzy Kluczewski

//---------------------------------------------------------------------------
// znajdź indeksy na których pozycji jest największa
// liczba wystąpień cyfr z tablicy Cyferki i posortuj rosnąco
void Cyferki_Sortuj(void)
{
int nr_cyfry, maksimum;
TCzestosc temp;

// sortuj met. bąbelkową rosnąco
// TCzestosc temp służy jako zmienna tymczasowa
for (int i=0; i<SIZE; i++)
{
for (int j=SIZE-1; j>=i; j--)
if (Cyferki[j-1].czestosc > Cyferki[j].czestosc)
{
temp.cyfra = Cyferki[j-1].cyfra;
temp.czestosc = Cyferki[j-1].czestosc;
Cyferki[j-1].cyfra = Cyferki[j].cyfra;
Cyferki[j-1].czestosc = Cyferki[j].czestosc;
Cyferki[j].cyfra = temp.cyfra;
Cyferki[j].czestosc = temp.czestosc;
};
};
};

}; // koniec przestrzeni nazw
#endif


Obowiązujący obecnie standard C++ umożliwia właśnie tworzenie własnych
przestrzeni nazw. Aby to wykonać należy skorzystać z następującego wzorca:







Ciąg dalszy pliku MojeSortowanie.h.






























Po takim zdefiniowaniu przestrzeni nazw, można w innym pliku używać jej
składowych; są dwa sposoby:

pierwszy polega na użyciu konstrukcji

nazwa_przestrzeni::nazwa_składowej

natomiast drugi polega na użyciu konstrukcji

using nazwa_przestrzeni;
nazwa_składowej

namespace nazwa_przestrzeni
{
// składowe przestrzeni nazw
};

background image

4

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II.

______________________________________________________________________

______________________________________________________________________

©2006 Jerzy Kluczewski

#include <iostream>
#include "MojeSortowanie.h"

using namespace std;

int main()
{
int cyfra;
sudoku::zeruj_czestosc_cyfr();

for (int i=0; i<10; i++)
{
cout << "Podaj cyfre: ";
cin >> cyfra;
sudoku::Cyferki[cyfra].cyfra = cyfra;
sudoku::Cyferki[cyfra].czestosc++;
}

sudoku::Cyferki_Sortuj();

cout << "Cyfra: ";
for (int i=0; i<SIZE; i++) cout<<cout.width(2)<< sudoku::Cyferki[i].cyfra;
cout << endl;
cout << "Czestosc: ";
for (int i=0; i<SIZE; i++)
cout << cout.width(2) << sudoku::Cyferki[i].czestosc;
cout << endl << endl;
system("pause");
return 0;
}


W drugim przypadku można korzystać ze wszystkich elementów składowych
zdefiniowanych w danej przestrzeni nazw, tak jakby były one zdefiniowane w
aktualnym pliku.

Pierwszy sposób zastosowano w pliku MojeSortowanie.cpp.

Oto plik źródłowy MojeSortowanie.cpp



Program główny MojeSortowanie.cpp.





background image

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II. 5
______________________________________________________________________

©2006 Jerzy Kluczewski

Przestrzeń nazw std


Często powstaje pytanie czy używać iostream czy iostream.h ? Współczesne
kompilatory C++ zawierają zazwyczaj dwie wersje biblioteki obsługującej strumienie
wejścia-wyjścia iostream: wersję starszą, której historia sięga początków języka C++,
oraz wersję nowszą, która powstała oficjalnie po standaryzacji języka w 1998 roku.

Teoretycznie pisząc #include <iostream.h> , korzystamy z wersji starszej, natomiast
pisząc #include <iostream> - z wersji nowszej. W praktyce zależy to od ustawień
kompilatora. W przypadku środowiska Borland C++ Builder , pisząc #include
<iostream.h>
, domyślnie i tak korzystamy z nowej biblioteki.

Zapis ten ma takie samo znaczenie jak:

#include <iostream>
using namespace std;


W nowej wersji biblioteki iostream wszystkie składowe zostały przeniesione do
przestrzeni nazw std, a zatem aby z nich skorzystać, należy użyć powyższej dyrektywy
using albo też nazwę każdej składowej poprzedzić nazwą std oraz podwójnym
dwukropkiem, na przykład aby odwołać się do standardowego strumienia wyjściowego
należy użyć konstrukcji

std::cout.























background image

6

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II.

______________________________________________________________________

______________________________________________________________________

©2006 Jerzy Kluczewski


II.

Obiekty



Czym są obiekty? Obiektem może być praktycznie wszystko (Rys. 1): dom, samochód,
osoba, atom, a w programowaniu obiektem jest każdy abstrakcyjny byt, który zapragnie
utworzyć programista w pamięci, np. macierz liczb całkowitych, albo stan pól jakiej gry
planszowej.

Obiekt może przechowywać dane, a także można na nim wykonywać różne operacje.
Obiekt może zawierać inne obiekty, tak samo jak wewnątrz samochodu znajdują się
fotele, kierownice, silnik.

Rys. 1 Obiekty

Projekt obiektu


W realnym świecie większość obiektów powstaje na podstawie projektu. W praktyce
programowania także występuje projektowanie obiektów. Najpierw powstaje projekt, a
potem są powoływane do życia (można powiedzieć tworzone) obiekty o budowie
i zachowaniu takim jakie przewiduje jego projekt. Taki projekt nazywamy klasą.

W programowaniu obiektowym – obiekty nie mogą istnieć bez swojego projektu,
natomiast projekt może istnieć bez obiektów.


Obiekt 1

Obiekt 2

Obiekt 3

Obiekt 4

Obiekt 5

background image

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II. 7
______________________________________________________________________

©2006 Jerzy Kluczewski


III.

Klasa



Klasa to projekt (wzorzec) obiektów, a obiekt to konkretna realizacja (egzemplarz)
zdefiniowanej uprzednio klasy (Rys. 2).

Klasa to także typ definiowany przez programistę, dlatego w środowisku Borland C+
Builder przyjęto konwencję, że nazwy klas rozpoczynają się od litery T.

Rys. 2 Klasa i jej obiekty

Klasę deklaruje się za pomocą słowa kluczowego class.

Oto wzór deklaracji klasy:









Uwaga: Nie należy zapominać o średniku znajdującym się po zamykającym nawiasie
klamrowym.

Słowo public oznacza, że dostęp do wnętrza klasy jest publiczny, czyli że do
elementów klasy można się odwoływać bez ograniczeń.

Obiekt 1

Obiekt 2

Obiekt 3

Obiekt 4

Klasa (projekt obiektów) –
opisuje właściwości i sposoby
zachowania się obiektów

class nazwa_klasy
{
public:
// definicja wnętrza klasy
};

background image

8

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II.

______________________________________________________________________

______________________________________________________________________

©2006 Jerzy Kluczewski



Klasa TPunkt


Oto deklaracja klasy TPunkt będąca projektem obiektów przechowujących dane
(współrzędne x i y punktów) o położeniu punktów na ekranie.









Zmienne x, y nazywa się składowymi klasy.

Pola klasy


Dane przechowywane w klasie (zmienne) nazywamy polami klasy.

Metody klasy


Kod umieszczany w klasie (funkcje działające na polach) nazywamy metodami klasy.

Klasa zawiera pola (dane) oraz metody (wykonywane czynności).

Deklaracje klasy (określające strukturę klasy), zazwyczaj umieszcza się w plikach
nagłówkowych z rozszerzeniem .h, natomiast definicje klasy w plikach .cpp.

Określenie struktury klasy












Plik Punkt.h

Do klasy TPunkt dodano dwie metody, które mają za zadanie pobierać wartości pól
klasy. Metody te noszą nazwy pobierzX i pobierzY.

class TPunkt
{
public:
int x;
int y;
};

class TPunkt
{
public:
int x;
int y;
int pobierzX();
int pobierzY();
};

background image

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II. 9
______________________________________________________________________

©2006 Jerzy Kluczewski



Powyższa deklaracja klasy TPunkt oznacza:

Definiuję nowy typ danych TPunkt.
Obiekty tego typu będą zawierały pola o nazwach x i y, oba typu int.
Obiekty tego typu będą zawierały dwie metody – jedna o nazwie pobierzX, druga
będzie się nazywała pobierzY, obie będą zwracały wartość typu int.

Teraz należy zdefiniować, co będą robiły te metody. Definicje metod należy wpisać do
pliku Punkt.cpp.

Definicje te muszą mieć następującą postać:








Do pliku Punkt.cpp dopisano definicje dwóch metod: pobierzX, pobierzY, pierwsza z
nich odczytuje wartość pola x z obiektu klasy TPunkt, a druga odczytuje wartość pola
y z obiektu klasy Punkt.















Plik Punkt.cpp

Uwaga: Przy tworzeniu pliku głównego programu Punkt.cpp, nie można zapomnieć
o dołączeniu do niego pliku nagłówkowego zawierającego deklaracje klasy (Punkt.h).

Po utworzeniu plików Punkt.h i Punkt.cpp można już zająć się tworzeniem obiektów
klasy TPunkt.

Służy do tego następująca konstrukcja:
nazwa_klasy nazwa_obiektu;

typ_zwracany nazwa_klasy :: nazwa_metody()
{
// treść metody
};

#include "Punkt.h"
#include <iostream.h>

int TPunkt::pobierzX()
{
return x;
}

int TPunkt::pobierzY()
{
return y;
}

background image

10

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II.

______________________________________________________________________

______________________________________________________________________

©2006 Jerzy Kluczewski

#include "Punkt.h"
#include <iostream.h>

int TPunkt::pobierzX()
{
return x;
}

int TPunkt::pobierzY()
{
return y;
}

int main()
{
TPunkt punkt;
punkt.x = 1;
punkt.y = 1;
cout << "Wartosc pola x z obiektu punkt to ";
cout << punkt.x << endl;
cout << "Wartosc pola y z obiektu punkt to ";
cout << punkt.y << endl;
system("pause");
return 0;
}




Aby program był w pełni funkcjonalny, należy dopisać funkcję main z odpowiednim
kodem.




























Program Punkt.cpp.

Po wykonaniu instrukcji TPunkt punkt, w pamięci komputera powstanie obiekt punkt
klasy TPunkt.

Można powiedzieć, że punkt to zmienna typu obiektowego TPunkt, albo że punkt
jest instancją (wystąpieniem) klasy TPunkt. (w skrócie będziemy używali słowa obiekt
zamiast zmienna typu obiektowego i klasa zamiast typ obiektowy
)

Gdyby w programie napisać:
TPunkt punkt1;
TPunkt punkt2;

to utworzone zostaną dwa obiekty (dwie instacje) klasy TPunkt.

Operator „kropka” pozwala na bezpośredni dostęp do pól obiektu punkt. Instrukcja
punkt.x = 1 pozwala na przypisanie wartości 1 do pola x w obiekcie punkt.

background image

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II. 11
______________________________________________________________________

©2006 Jerzy Kluczewski

int main()
{
TPunkt pierwszyPunkt, drugiPunkt;
pierwszyPunkt.x = 100;
pierwszyPunkt.y = 200;
drugiPunkt.x = 300;
drugiPunkt.y = 400;
cout << "Wartosci pol obiektu pierwszyPunkt:" << endl;
cout << "x= "<< pierwszyPunkt.pobierzX() << ", ";
cout << "y= "<< pierwszyPunkt.pobierzY() << endl;
cout << "Wartosci pol obiektu drugiPunkt:" << endl;
cout << "x= "<< drugiPunkt.pobierzX() << ", ";
cout << "y= "<< drugiPunkt.pobierzY() << endl;
return 0;
}


Odwołania do składowych obiektu


Stosowanie obiektów pozbawione byłoby sensu, gdyby nie można było się odwoływać
(odczytywać lub zapisywać do pól obiektu) do ich składowych lub też wywoływać ich
metody.

Do tego celu stosujemy operator

 (kropka). Na przykład dla zmiennej obiektowej

punkt do jej pola x należy wpisać wartość 20 – wykonuje się to za pomocą następującej
instrukcji:
punkt.x = 10;

Odczyt wartości pola x ze zmiennej obiektowej punkt – wykonuje się to za pomocą
następującej instrukcji:
wartość = punkt.x;

Podobnie jest w przypadku metod. Wywołanie metody polega na podaniu nazwy
zmiennej obiektowej, znaku kropki i nazwy metody n.p.

int wspX = punkt.pobierzX();

Wiele obiektów tej samej klasy


W jednym programie może istnieć wiele obiektów tej samej klasy. Program
Punkt2.cpp demonstruje taką sytuację. Do odczytu zawartości pól obiektu
wykorzystywane są metody pobierzX, pobierzY. Za pomocą kodu programu tworzone
są dwa obiekty pierwszyPunkt, drugiPunkt, przypisywane są różne wartości do pól
obiektów, a za pomocą odpowiednich metod uzyskiwane są wartości tych pól.


















Program Punkt2.cpp.

background image

12

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II.

______________________________________________________________________

______________________________________________________________________

©2006 Jerzy Kluczewski

IV.

Właściwości obiektu


Za pomocą metod można zmieniać właściwości obiektu. W poprzednim przykładzie
klasa TPunkt nie posiadała takich możliwości. Nic nie stoi na przeszkodzie, aby w
klasie dopisać metody ustawiające wartości pól x i y. Metody te muszą jednak mieć
możliwość pobierania argumentów (czyli wartości, które będą przesyłały do wnętrza
obiektu). Metody te tworzą tzw. interfejs klasy, pozwalający na dostęp do obiektów tej
klasy (Rys. 3).


Rys. 3. Metody jako interfejs dostępu programu do pól obiektu.

Argumenty metod


Każda metoda, tak jak funkcja w C++, może przyjmować argumenty, czyli dane.
Argumenty umieszcza się w nawiasach okrągłych, oddzielając je od siebie znakami
przecinka. Oto schemat takiej konstrukcji:

typ_zwracanego wyniku

nazwa_metody

(typ_1 argument_1, typ_2 argument_2,

… typ_n argument_n)

Przykład interfejsu do obiektu klasy punkt (Rys.4).







Rys. 4. Metody ustawiające wartości pól obiektu klasy TPunkt.

Pole y

Pole x

Metody:

pobierzX
pobierzY


ustawX
ustawY

Obiekt punkt

Program
główny

dostęp


void

ustawX

(int wspX)

void

ustawY

(int wspY)

wsp

X

wsp

Y

background image

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II. 13
______________________________________________________________________

©2006 Jerzy Kluczewski


Projekt zmodyfikowanej klasy TPunkt będzie teraz wyglądał następująco:















Plik Punkt.h


Natomiast definicje metod w programie Punkt3.cpp będą wyglądały następująco:


























Plik Punkt3.cpp

class TPunkt
{
public:
int x;
int y;

int pobierzX();
int pobierzY();

void ustawX(int wspX);
void ustawY(int wspY);
};

#include <iostream>
#include "Punkt.h"
using namespace std;
int TPunkt::pobierzX()
{
return x;
}

int TPunkt::pobierzY()
{
return y;
}

void TPunkt::ustawX(int wspX)
{
x = wspX;
}

void TPunkt::ustawY(int wspY)
{
y = wspY;
}

background image

14

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II.

______________________________________________________________________

______________________________________________________________________

©2006 Jerzy Kluczewski

void TPunkt::ustawX(int x)
{
x = x;
}

void TPunkt::ustawX(int x)
{
this->x = x;
}

void TPunkt::ustawY(int y)
{
this->y = y;
}



Odwołanie this


Co się stanie, gdy w metodzie danej klasy użyjemy argumentu o identycznej nazwie jak
jedno z pól, (patrz przykład poniżej) ?







Powyższa definicja metody jest formalnie poprawna, lecz jest bez sensu!!! Aby
odróżnić w niej nazwę pola x klasy TPunkt od nazwy argumentu x, należy posłużyć się
słowem kluczowym this, które oznacza obiekt bieżący (jest synonimem obiektu
bieżącego). Należy zastosować konstrukcję

this







nazwa_pola.


Operator

 jest równoznaczny z operatorem (kropka), dlatego w tym przypadku

operacja this







x jest traktowana tak samo jak punkt.x. Poprawne użycie argumentu x

w definicji metod ustawX, ustawY wygląda następująco:












Konstrukcja

Interpretacja konstrukcji

int x;

zmienna x typu int

this







x

pole x w aktualnym obiekcie

punkt.x

pole x w obiekcie punkt


Podobnie można użyć operatora

 dla innych składowych obiektu, na przykład:


this







y = 10;

x = this







pobierzX();

this







ustawY(5);


background image

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II. 15
______________________________________________________________________

©2006 Jerzy Kluczewski

void ustawWspolrzedne(TPunkt punkt);

void TPunkt::ustawWspolrzedne(TPunkt punkt)
{
x = punkt.x;
y = punkt.y;
}


Sekwencja działania instrukcji pierwszyPunkt.ustawX(100); na obiekcie
pierwszyPunkt klasy TPunkt wygląda następująco.


Rys. 5. Ustawianie wartości pola x obiektu pierwszyPunkt.

V.

Przeciążanie metod

Obiekt jako argument


Argumentem przekazywanym metodzie może być również obiekt, na przykład:



Definicja metody:







pierwszyPunkt

pierwszyPunkt.ustawX(100);

void TPunkt::ustawX(int x)

zmienna x ma wartość 100

100

100


Pole x


Pole y

100

?

background image

16

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II.

______________________________________________________________________

______________________________________________________________________

©2006 Jerzy Kluczewski

class TPunkt
{
public:
int x;
int y;

int pobierzX();
int pobierzY();
void ustawX(int wspX);
void ustawY(int wspY);
void ustawWspolrzedne(TPunkt punkt);
};

#include <iostream>
#include "Punkt5.h"
using namespace std;
int TPunkt::pobierzX()
{ return x; }
int TPunkt::pobierzY()
{ return y; }
void TPunkt::ustawX(int wspX)
{ x = wspX; }
void TPunkt::ustawY(int wspY)
{ y = wspY; }
void TPunkt::ustawWspolrzedne(TPunkt punkt)
{ x = punkt.x; y = punkt.y; }

int main()
{
TPunkt pierwszyPunkt, drugiPunkt;
pierwszyPunkt.ustawX(100);
pierwszyPunkt.ustawY(200);
drugiPunkt.ustawWspolrzedne(pierwszyPunkt);
cout << "x= "<< pierwszyPunkt.pobierzX() << ", ";
cout << "y= "<< pierwszyPunkt.pobierzY() << endl;
cout << "x= "<< drugiPunkt.pobierzX() << ", ";
cout << "y= "<< drugiPunkt.pobierzY() << endl;
system("pause");
return 0;
}


Przykład programu wykorzystującego ten sposób przekazywania parametrów:














Plik Punkt5.h






























Plik Punkt5.cpp

background image

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II. 17
______________________________________________________________________

©2006 Jerzy Kluczewski

class TPunkt
{
public:
int x;
int y;

int pobierzX();
int pobierzY();
void ustawX(int wspX);
void ustawY(int wspY);
void ustawWspolrzedne(TPunkt punkt);
void ustawWspolrzedne(int wspX, int wspY);
};

void TPunkt::ustawWspolrzedne(TPunkt punkt)
{
x = punkt.x;
y = punkt.y;
}
void TPunkt::ustawWspolrzedne(int wspX, int wspY)
{
x = wspX;
y = wspY;
}

Overloading


W języku C++ możliwe jest tzw. przeciążanie metod (ang. overloading). Polega ono na
zdefiniowaniu wielu metod o tej samej nazwie, ale różniących się argumentami
wywołania. Otóż w jednej klasie może istnieć wiele metod o takich samych nazwach,
co nie znaczy wcale że są to te same metody. Różnią się one bowiem listą argumentów
przekazywanych w trakcie ich wywoływania. Tą możliwość języka C++ nazywamy
przeciążaniem metod.

Oto przykład zmodyfikowanej deklaracji klasy TPunkt zawierającej dwie metody o tej
samej nazwie void ustawWspolrzedne :

















Plik Punkt5.h

Argumenty oraz kody tych metod różnią się między sobą i wyglądają następująco:













Plik Punkt5.cpp

background image

18

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II.

______________________________________________________________________

______________________________________________________________________

©2006 Jerzy Kluczewski

#include <iostream>
#include "Punkt5.h"
using namespace std;
int TPunkt::pobierzX()
{
return x;
}
int TPunkt::pobierzY()
{
return y;
}
void TPunkt::ustawX(int wspX)
{
x = wspX;
}
void TPunkt::ustawY(int wspY)
{
y = wspY;
}
void TPunkt::ustawWspolrzedne(TPunkt punkt)
{
x = punkt.x;
y = punkt.y;
}
void TPunkt::ustawWspolrzedne(int wspX, int wspY)
{
x = wspX;
y = wspY;
}
int main()
{
TPunkt pierwszyPunkt, drugiPunkt;
pierwszyPunkt.ustawWspolrzedne(100, 200);
drugiPunkt.ustawWspolrzedne(pierwszyPunkt);
cout << "x= "<< pierwszyPunkt.pobierzX() << ", ";
cout << "y= "<< pierwszyPunkt.pobierzY() << endl;
cout << "x= "<< drugiPunkt.pobierzX() << ", ";
cout << "y= "<< drugiPunkt.pobierzY() << endl;
system("pause");
return 0;
}


Po skompilowaniu i uruchomieniu poniższego przykładowego programu Punkt5.cpp:












































Na ekranie pojawią się następujące wyniki:
x= 100, y= 200
x= 100, y= 200

background image

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II. 19
______________________________________________________________________

©2006 Jerzy Kluczewski

void FunA(int X)
{
X++;
}

VI.

Sposoby przekazywania argumentów



Argumenty metod mogą być przekazywane na dwa sposoby:

przez wartość (ang. value)

przez referencję (ang. reference)


Sposób pierwszy polega na tym, że wartość przekazywana funkcji (zmienna K) nie
ulega zmianie po zakończeniu działania funkcji funA. Wewnątrz funkcji FunA nie ma
dostępu do zmiennej K.


Rys. 6. Przekazywanie wartości argumentu X przez wartość.

Definicja funkcji funA:







FunA(K);

void FunA(int X)

zmienna X ma wartość 10
zmienna K ma wartość 10

10

10

K = 10;

zmienna K ma wartość 10

X++;

zmienna X ma wartość 11
zmienna K ma wartość 10

cout << K << endl;

zmienna K ma wartość 10

background image

20

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II.

______________________________________________________________________

______________________________________________________________________

©2006 Jerzy Kluczewski

void FunB(int &X)
{
X++;
}


Sposób przez referencję


Sposób drugi polega na tym, że wartość przekazywana funkcji (zmienna K) ulega
zmianie po zakończeniu działania funkcji, zostaje zmodyfikowana przez funkcję funB.
Wewnątrz funkcji FunB wszelkie zmiany dokonywane na zmiennej X odbywają się tak
jakby to była zmienna K.


Rys. 7. Przekazywanie wartości argumentu X przez referencję.

Definicja funkcji funB:







Obie funkcje FunA i FunB na pozór różnią się nieznacznie a mianowicie jednym
znakiem &. Znak ten oznacza operator referencji.

FunB(K);

void FunB(int &X)

zmienna K jest traktowana tak
samo jak zmienna X

10

10

K = 10;

zmienna K ma wartość 10

X++;

zmienna X ma wartość 11
zmienna K ma wartość 11

cout << K << endl;

zmienna K ma wartość 11

11

background image

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II. 21
______________________________________________________________________

©2006 Jerzy Kluczewski

klasa* nazwa_obiektu = new klasa();

TPunkt* punkt = new TPunkt();

(*punkt).x = 100;

VII.

Dynamiczne obiekty



Aby utworzyć zmienną dynamiczną, korzysta się z operatora new w następującej
konstrukcji:

typ* nazwa_zmiennej = new typ;

Przykład:
int* pLiczba = new int;

Odwołanie do miejsca wskazywanego przez pLiczba odbywa się za pomocą operatora
*, na przykład:

*pLiczba = 100;

W przypadku klas i obiektów jest podobnie. Aby dynamicznie utworzyć nowy obiekt
danej klasy, należy zastosować konstrukcję:




Dla klasy TPunkt zdefiniowanej w poprzednich rozdziałach, dynamiczny obiekt
będzie tworzony za pomocą następującej instrukcji:



W tym przypadku nazwa punkt nie będzie obiektem, tylko wskaźnikiem do obiektu.

Odwoływanie się do składowych obiektu do którego nie ma bezpośredniego dostępu,
jest już trochę trudniejsze, polega ono na użyciu:



operatora wyłuskania (*),



operatora dostępu do składowych (

)



oraz nawiasów okrągłych.


Przypisanie składowej x (pole x) w obiekcie wskazywanym przez wskaźnik punkt,
wartości 100 będzie miało następująca postać:



Po lewej stronie znaku = wykonane będą kolejno następujące czynności: wyłuskanie
obiektu, a potem udostępnione pole x.

background image

22

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II.

______________________________________________________________________

______________________________________________________________________

©2006 Jerzy Kluczewski

(*punkt).ustawX(100);

wskaźnik







nazwa_pola

wskaźnik







nazwa_metody(argumenty)

punkt)







x = 100;

punkt)







ustawX(100);

void Punkt::inicjuj()
{
this







x = 0;

this







y = 0;

}



Z kolei uruchomienie metody ustawX na obiekcie wskazywanym przez wskaźnik
punkt, będzie miało następująca postać:




Istnieje jeszcze inny sposób dostępu (częściej stosowany) do składowych obiektu –
polega on na użyciu operatora

.


Dostęp do obiektu danej klasy, wskazywanego przez wskaźnik wykonuje się stosując
następującą konstrukcję:



lub




Przykłady użycia tej drugiej metody:






Przypomnienie: gdy obiekty lub zmienne proste są tworzone dynamicznie za pomocą
operatora new, koniecznie należy pamiętać, aby po ich wykorzystaniu usunąć je ze
sterty za pomocą operatora delete. W przeciwnym razie nastąpią tzw. wycieki pamięci.

Inicjalizacja pól


W momencie tworzenia obiektu, warto wiedzieć jakie wartości początkowe mają jego
pola. Wartości początkowe zależą od kompilatora, i zazwyczaj mają one wartości
trudne do przewidzenia. Problem ten można usunąć pisząc własna metodę inicjalizacji
np.







Ale również może się zdarzyć, że programista zapomni o jej wywołaniu, nie jest to
dobre rozwiązanie.

background image

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II. 23
______________________________________________________________________

©2006 Jerzy Kluczewski

class nazwa_klasy
{
public:
// definicje pól

nazwa_klasy

();

// definicje metod
};

class TPunkt
{
public:
int x;
int y;
TPunkt();
// definicje pozostałych metod
};

TPunkt ::TPunkt()
{
x = 0;
y = 0;
}


Konstruktor


Z pomocą w inicjowaniu pól obiektów przychodzi nam konstruktor.
Konstruktor to specjalna metoda wywoływana automatycznie podczas tworzenia
obiektu
, nadaje się zatem doskonale do jego wstępnej inicjalizacji.

Tworząc dobrze przemyślany konstruktor, nie trzeba się przejmować inicjalizowaniem
wartości składowych podczas tworzenia obiektu.

Metoda będąca konstruktorem nie zwraca żadnego wyniku. Przed nazwą konstruktora
nie może pojawić się nawet słowo void. Nazwa takiej metody musi być identyczna z
nazwą klasy, której dotyczy. Konstruktor wchodzi w skład klasy.

Ogólna deklaracja klasy posiadającej konstruktor wygląda następująco










Przykład deklaracji klasy TPunkt











Przykład definicji konstruktora TPunkt









background image

24

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II.

______________________________________________________________________

______________________________________________________________________

©2006 Jerzy Kluczewski

class nazwa_klasy
{
public:
// definicje pól

~

nazwa_klasy

();

// definicje metod
};

class TPunkt
{
public:
int x;
int y;

~

TPunkt();

// definicje pozostałych metod
};

TPunkt ::

~

TPunkt()

{
cout<<”Wywołano destruktor”<< endl;
}


Destruktor


Konstruktory to metody wykonywane podczas tworzenia nowego obiektu. Z kolei
destruktory to metody wykonywane podczas usuwania obiektu (wykonanie instrukcji
delete dla obiektów tworzonych dynamicznie lub gdy obiekt będzie usuwany z pamięci
podczas kończenia pracy programu – dla obiektów statycznych).

Aby zdefiniować destruktor używa się podobnej konstrukcji jak dla konstruktora, tylko

przed jego nazwą umieszcza się znak

~

(tylda).


Ogólna deklaracja klasy posiadającej konstruktor wygląda następująco










Przykład deklaracji klasy TPunkt










Przykład definicji konstruktora

~

TPunkt







Destruktor przydaje się w sytuacjach gdy trzeba posprzątać po obiekcie. Gdy podczas
pracy obiektu, konstruktor zarezerwuje pamięć lub inne zasoby systemowe, to przed
usunięciem obiektu
należy za pomocą destruktora wszystkie jego zasoby zwolnić.


background image

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II. 25
______________________________________________________________________

©2006 Jerzy Kluczewski

// Program demonstracyjny
#include <iostream>
using namespace std;

class Example
{
public:
int* pole1;
Example()
{
pole1 = new int;
*pole1 = 0;
cout <<"Wywolanie konstruktora"<<endl;
}

~Example()
{
delete pole1;
cout <<"Wywolanie destruktora"<<endl;
}
};

int main()
{
Example example;
system("pause");
return 0;
}


Poniższy program DemoUnit1.cpp demonstruje działanie konstruktora i destruktora































Program DemoUnit1.cpp

Zadanie VII-1


W funkcji main() dopisz dwie instrukcje: zapisującą wartość 100 do wartości
wskazywanej przez pole1 w obiekcie example, odczytującą wartość wskazywaną przez
pole1 z obiektu example.

Zadanie VII-2


W jaki sposób w funkcji main() będzie wyglądał zapis i odczyt wartości wskazywanej
przez pole1 obiektu klasy Example, jeśli zostanie on utworzony przy pomocy
instrukcji Example *example = new Example() ?

background image

26

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II.

______________________________________________________________________

______________________________________________________________________

©2006 Jerzy Kluczewski

class TPunkt
{
public:
int x;
int y;

TPunkt(int x, int y);
};

TPunkt::TPunkt( int x = 0, int y = 0);
{
this







x = x;

this







y = y;

};

Zadanie VII-3


Jak będzie wyglądał kod klasy TPunkt w którym wartości x i y byłyby przechowywane
na stercie, a w obiektach klasy TPunkt znajdowałyby się tylko wskaźniki int* x, int* y.

Zadanie VII-4


Proszę napisać kod klasy TKontener, zachowująca się podobnie jak dynamiczna
tablica przechowująca dodatnie wartości całkowite. Będzie ona miała dwie metody
get() i set() pobierające i ustawiające wartości poszczególnych komórek. Rozmiar
tablicy będzie się w razie konieczności zwiększał automatycznie podczas dodawania
nowych danych. Przykładowo set(2,10) ma spowodować przypisanie wartości 10 do
drugiej komórki, a get(20) ma pobrać wartość dwudziestej komórki.

VIII.

Konstruktory



Argumenty konstruktorów


Konstruktory, tak jak inne metody mogą być bezargumentowe lub przyjmować
argumenty. Mogą też mieć argumenty domyślne. Deklaracja klasy TPunkt zawierającej
konstruktor może wyglądać następująco:










a definicja konstruktora:








background image

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II. 27
______________________________________________________________________

©2006 Jerzy Kluczewski

#include <iostream>
#include "konstruktor1Unit.h"
using namespace std;
TPunkt::TPunkt( int x = 0, int y = 0)
{
This







x = x;

This







y = y;

};

int main()
{
TPunkt punkt1;
TPunkt punkt2(100);
TPunkt punkt3(200, 300);
cout << "punkt1: "<<endl;
cout << "x= "<<punkt1.x<<" y= "<<punkt1.y<<endl;
cout << "punkt2: "<<endl;
cout << "x= "<<punkt2.x<<" y= "<<punkt2.y<<endl;
cout << "punkt3: "<<endl;
cout << "x= "<<punkt3.x<<" y= "<<punkt3.y<<endl;
cout << "punkt4: "<<endl;
cout << "x= "<<punkt4







x<<" y= "<<punkt4





y<<endl;

system("pause");
return 0;
}

Program demonstrujący trzy sposoby tworzenia obiektu klasy TPunkt:

nie podając żadnego argumentu TPunkt punkt1,

podając tylko jeden argument TPunkt punkt2(100),

podając oba argumenty TPunkt punkt3(200, 300).



























Program konstruktory1Unit.cpp

Wynik działania programu:
punkt1:
x= 0 y= 0
punkt2:
x= 100 y= 0
punkt3:
x= 200 y= 300
punkt4:
x= 1 y= 2

W przypadku czwartego punktu, na stercie zainicjalizowano obszar, zawierający dwa
pola x i y , które zainicjowano wartościami 1 i 2. Nazwa punkt4 jest wskaźnikiem do
tego obszaru (obiektu).


background image

28

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II.

______________________________________________________________________

______________________________________________________________________

©2006 Jerzy Kluczewski

#include <iostream>
#include "konstruktor2Unit.h"
using namespace std;
TPunkt::TPunkt( int x = 0, int y = 0)
{
this->x = x;
this->y = y;
};

int main()
{
TPunkt punkt1(100, 200);
TPunkt punkt2(punkt1);
cout << "punkt1: "<<endl;
cout << "x= "<<punkt1.x<<" y= "<<punkt1.y<<endl;
cout << "punkt2: "<<endl;
cout << "x= "<<punkt2.x<<" y= "<<punkt2.y<<endl;
system("pause");
return 0;
}

Konstruktor kopiujący


Do stworzenia kilku obiektów tej samej klasy można użyć konstruktora kopiującego.

Co to jest konstruktor kopiujący? Konstruktor kopiujący to taki konstruktor, którego
zadaniem jest utworzenie obiektu będącego kopią obiektu już istniejącego.

Jeśli konstruktor kopiujący nie zostanie zdefiniowany oddzielnie, to i tak zostanie on
automatycznie stworzony – oto przykład programu zawierającego konstruktor
automatyczny (program konstruktory2Unit.cpp):






















Program konstruktory2Unit.cpp

Instrukcja TPunkt punkt1(100, 200); spowodowała utworzenie obiektu punkt1 o
współrzędnych x=100 i y=200. następna instrukcja TPunkt punkt2(punkt1);
utworzyła punkt2 obiekt klasy TPunkt, będący kopią obiektu punkt1. Dlatego jego
pola x i y zawierają te same wartości co punkt1.

Uwaga:
Nawet jeśli nie umieszczono w kodzie własnego konstruktora kopiującego, to i tak
zostanie on dodany automatycznie. Jego działanie ogranicza się tylko do skopiowania
obszaru pamięci zajmowanego przez obiekt źródłowy (punkt1) do obszaru
zajmowanego przez obiekt docelowy (punkt2).

Zagadnienie konstruktora kopiującego nabiera odpowiedniego stopnia powagi, gdy
zmienimy definicje pól w klasie z typu prostego int na wskaźniki do typu int.

background image

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II. 29
______________________________________________________________________

©2006 Jerzy Kluczewski

class TPunkt
{
public:
int *x;
int *y;

TPunkt(int x, int y)
{
this







x = new int(x);

this







y = new int(y);

};

~

TPunkt()

{
delete this







x;

delete this







y;

};
};



Konstruktor kopiujący i pola wskaźnikowe


W tym rozdziale nastąpi zasadnicza zmiana podejścia do konstruktorów i wskaźników.
W poniższym przykładzie definicja klasy TPunkt będzie zawierać pola x i y będące
wskaźnikami do typu int. Ze względu na charakter pól klasy, ulegną zmianie definicje
konstruktora i destruktora.




















Plik konstruktor3Unit.h.

Konstruktor tworzy na stercie dwa obszary typu int, ładuje do nich wartości
argumentów x i y, a do pól x i y przypisuje wskaźniki do zarezerwowanych obszarów.

Destruktor usuwa ze sterty dwa obszary wskazywane przez wskaźniki x i y.

Reasumując, nazwy x i y nie przechowują danych, lecz wskaźniki do danych, które są
zapamiętane na stercie.

Zadanie VIII-1


Demonstracja podejścia wskaźnikowego.
Zmień program konstruktor2Unit.cpp na program konstruktor3Unit.cpp w ten
sposób, aby zmienić w funkcji main(), sposób dostępu do składowych obiektów:



background image

30

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II.

______________________________________________________________________

______________________________________________________________________

©2006 Jerzy Kluczewski

int main()
{
TPunkt punkt1(100, 200);
TPunkt punkt2(punkt1);
cout << "punkt1: "<<endl;
cout << "x= "<<*(punkt1.x)<<" y= "<<*(punkt1.y)<<endl;
*(punkt2.x) = 1;
*(punkt2.y) = 2;
cout << "punkt1: "<<endl;
cout << "x= "<<*(punkt1.x)<<" y= "<<*(punkt1.y)<<endl;
system("pause");
return 0;
}


Zmień zawartość funkcji main() na następującą:

















Po kompilacji i uruchomieniu programu konstruktor3Unit.cpp, nastąpi niemiła
niespodzianka – program wykonał nieprawidłowe operacje i nastąpiła interwencja
systemu operacyjnego.

Rys. 8. Komunikat informujący że w destruktorze próbowano zwolnić pamięć, która już
wcześniej została zwolniona.

Druga niespodzianka to fakt, że za pomocą instrukcji
*(punkt2.x) = 1;
*(punkt2.y) = 2;

miał zostać zmodyfikowany punkt2, a okazało się, że został zmodyfikowany punkt1.

Rys. 9. Komunikat pokazujący wcześniejsze wartości x i y oraz późniejsze wartości x i
y obiektu punkt1.

background image

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II. 31
______________________________________________________________________

©2006 Jerzy Kluczewski

Aby przerwać działanie programu i wrócić do jego projektowania należy użyć
polecenia Run







Program reset (Ctrl+F2).


Przyczyna błędu EAccessViolation:
W instrukcji delete this







x; destruktora dla obiektu punkt2, próbuje się zwolnić

pamięć już zwolnioną w trakcie uruchomienia destruktora dla obiektu punkt1.

Przyczyna błędu polegającego na złych wynikach:
Problem powstał gdy domyślny konstruktor kopiujący skopiował wskaźniki z obiektu
punkt1
do obiektu punkt2. (Rys. 10). Skutkiem tego niedbalstwa, wskaźnik x oraz y po
prostu rozróżnia obiektu (nie ważne czy należy do obiektu punkt1, czy punkt2, zawsze
wskazuje na ten sam obszar). Natomiast wartości wskazywane nie zostały skopiowane.



Rys. 10. Obiekty punkt1, punkt2 zawierają wskaźniki wskazujące na te sam obszar.

Aby program działał poprawnie, należy napisać własny konstruktor kopiujący, który dla
każdego tworzonego jego za pomocą. obiektu będzie rezerwował oddzielną pamięć.

W pliku konstruktor3Unit.h za definicją konstruktora TPunkt(int x, int y) dopisać
należy nową (własną) definicję konstruktora kopiującego :

TPunkt(TPunkt &punkt) // konstruktor kopiujący
{
this->x = new int( *(punkt.x) );
this->y = new int( *(punkt.y) );
};


punkt1






punkt2







int *x

int *y

int *x

int *y









obszar x

obszar y

background image

32

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II.

______________________________________________________________________

______________________________________________________________________

©2006 Jerzy Kluczewski

class TPunkt
{
public:
int *x;
int *y;

TPunkt(int x, int y)
{
this->x = new int(x);
this->y = new int(y);
};
TPunkt(TPunkt &punkt) // konstruktor kopiujący
{
this->x = new int(*(punkt.x));
this->y = new int(*(punkt.y));
};
~TPunkt()
{
delete this->x;
delete this->y;
};
};


Tworzenie poprawnego konstruktora kopiującego ilustruje poniższy plik
konstruktor3Unit.h oraz Rys. 11.
























Plik konstruktor3Unit.h.

Rys. 11. Obiekty punkt1, punkt2 zawierają wskaźniki wskazujące na osobne obszary.

punkt1






punkt2







int *x

int *y

int *x

int *y















obszar x

obszar y

obszar x

obszar y

background image

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II. 33
______________________________________________________________________

©2006 Jerzy Kluczewski

class nazwa_klasy
{
public:

static nazwa_typu nazwa_pola

;

};

nazwa_typu

nazwa_klasy

::

nazwa_pola

;

nazwa_typu

nazwa_klasy

::

nazwa_pola

= wartosc_poczatkowa;


IX.

Składowe statyczne



Klasy mogą zawierać składowe statyczne, czyli takie pola i metody, które są dostępne,
(wspólne) dla wszystkich obiektów danej klasy. Służą one do komunikowania się
obiektów między sobą.

Pola statyczne


Aby umieścić statyczne pole wewnątrz klasy, należy wykonać następujące czynności:

zadeklarować pole wewnątrz klasy


Ogólna deklaracja klasy posiadającej pole statyczne wygląda następująco







zdefiniować pole na zewnątrz klasy (poza deklaracją klasy) – czyli
zarezerwować pamięć dla zmiennej statycznej. Należy wykorzystać operator
zasięgu ::


Ogólna definicja pola (zmiennej) statycznej wygląda następująco





Od tego miejsca w programie faktycznie pole statyczne istnieje i można się do niego

odwoływać za pomocą operatora zakresu

::

albo operatora

 (kropka).


Tak zdefiniowana zmienna statyczna ma wartość początkową równa 0 (wykonuje to
kompilator) Aby ją zainicjować inną wartością należy użyć konstrukcji







background image

34

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II.

______________________________________________________________________

______________________________________________________________________

©2006 Jerzy Kluczewski

//program4Unit.cpp
#include <iostream>
using namespace std;

class Klasa
{
public:
static int liczba;
};

int Klasa::liczba;

int main()
{
Klasa::liczba = 10;
cout << "Klasa::liczba="<<Klasa::liczba<<endl;
cout<<endl;

Klasa example1;
Klasa example2;

example1.liczba = 20;
cout << "example1.liczba="<<example1.liczba<<endl;
cout << "Klasa::liczba="<<Klasa::liczba<<endl;

example2.liczba = 30;
cout << "example2.liczba="<<example2.liczba<<endl;
cout << "Klasa::liczba="<<Klasa::liczba<<endl;

system("pause");
return 0;
}


Przykład deklaracji klasy Klasa zawierającej pole statyczne liczba i definicji pola
statycznego liczba ilustruje program program4Unit.cpp, można przekonać się, że
odwołanie do pola statycznego poprzez dowolny obiekt example1 lub example2 jest

równoznaczne z odwołaniem się poprzez operator zasięgu

::




































Program program4Unit.cpp







background image

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II. 35
______________________________________________________________________

©2006 Jerzy Kluczewski

class nazwa_klasy
{
public:

static typ_zwracany nazwa_metody

(argumenty_metody);

};

typ_zwracany

nazwa_klasy

::

nazwa_metody

(argumenty_metody)

{
// kod metody
}

Metody statyczne


W języku C++ mogą istnieć również statyczne metody. Każda statyczna metoda jest
wspólna dla wszystkich obiektów danej klasy.

Aby umieścić statyczne metodę wewnątrz klasy, należy wykonać następujące
czynności:

zadeklarować metodę wewnątrz klasy


Ogólna deklaracja klasy posiadającej metodę statyczną wygląda następująco







zdefiniować jej kod na zewnątrz klasy. Należy wykorzystać operator zasięgu ::


Ogólna definicja metody statycznej wygląda następująco









Przykład deklaracji i definicji metody statycznej Display(), która będzie wyświetlała
wartość pola statycznego liczba, zawiera zmodyfikowany program program4Unit.cpp,
którego treść umieszczono na następnej stronie.

Dostęp do pól i metod


Zwykłe metody mają dostęp do wszystkich danych klasy (dostęp do wszystkich pól).

Metody statyczne maja dostęp jedynie do danych statycznych, czyli mogą :

odwoływać się tylko do pól statycznych

wywoływać tylko inne metody statyczne




background image

36

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II.

______________________________________________________________________

______________________________________________________________________

©2006 Jerzy Kluczewski

//program4Unit.cpp
#include <iostream>
using namespace std;

class Klasa
{
public:
static int liczba;
static void Display();
};

int Klasa::liczba;
void Klasa::Display()
{
cout << "(metoda) liczba = " << liczba << endl;
}

int main()
{

Klasa::liczba = 10;
cout << "Klasa::liczba="<<Klasa::liczba<<endl;
cout<<endl;

Klasa example1;
Klasa example2;

example1.liczba = 20;
cout << "example1.liczba="<<example1.liczba<<endl;
cout << "Klasa::liczba="<<Klasa::liczba<<endl;
example1.Display();

example2.liczba = 30;
cout << "example2.liczba="<<example2.liczba<<endl;
cout << "Klasa::liczba="<<Klasa::liczba<<endl;
example2.Display();

system("pause");
return 0;
}














































Program zmodyfikowany program4Unit.cpp:

background image

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II. 37
______________________________________________________________________

©2006 Jerzy Kluczewski

#include <iostream>
using namespace std;

class Klasa
{
public:
int a;
static int b;
void fun(void);
void funA();
void funB();
static void funAA();
static void funBB();
};

int Klasa::b = 1;

void Klasa::funA(void)
{
a = 10;
b = 20;
funB();
funAA();
}

void Klasa::funAA()
{
a = 100; // odwołanie do niestatycznego pola
b = 200;
funB(); // odwołanie do niestatycznej metody
funBB();
}

void Klasa::funB() {}
void Klasa::funBB() {}

int main()
{ return 0; }

Dostęp do pól i metod – c.d.



Oto program program5Unit.cpp ilustrujący sytuację odwołania się z poziomu metody
statycznej, do niestatycznych obiektów.









































Program program5Unit.cpp:

background image

38

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II.

______________________________________________________________________

______________________________________________________________________

©2006 Jerzy Kluczewski



Po kompilacja programu program5Unit.cpp zakończy się dwoma komunikatami

program5Unit.cpp: E2231 Member Klasa::a Cannot be used whitout an object.
program5Unit.cpp: E2283 Member Use . or -> to call Klasa::funB().

Pierwszy błąd powstał w instrukcji

a = 100;

spowodowany tym, że metoda statyczna funAA odwołuje się do niestatycznego pola a.

Drugi błąd powstał w instrukcji

funB();

spowodowany tym, że metoda zwykła funB() jest wywoływana w metodzie statycznej
funAA().

Zadanie IX-1


Napisz kod przykładowej klasy TOsoba, której zadaniem będzie przechowywanie
imion i nazwisk osób. Pola imie i nazwisko powinny być typu char* , a pamięć
niezbędna do przechowywania danych ma być rezerwowana dynamicznie w
konstruktorze podczas tworzenia obiektu. Pamiętaj o uwzględnieniu konstruktora
kopiującego oraz destruktora.

Zadanie IX-2


Napisz kod przykładowej klasy TNapis, której zadaniem będzie przechowywanie ciągu
znaków. Pole dane powinno być typu char* , a pamięć niezbędna do przechowywania
danych ma być rezerwowana dynamicznie w konstruktorze podczas tworzenia obiektu.
Klasa powinna posiadać metodę o nazwie Dlugosc zwracającą liczbę znaków danej
przechowywanej w polu dane. Pamiętaj o uwzględnieniu konstruktora kopiującego oraz
destruktora.

Zadanie IX-3


Napisz kod przykładowej klasy TKlasa, zawierającej pole statyczne count, którego
zadaniem będzie przechowywanie aktualnej liczby obiektów tej klasy.



background image

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II. 39
______________________________________________________________________

©2006 Jerzy Kluczewski

class TPunkt
{
public:
int x;
int y;
TPunkt();
~TPunkt();
int pobierzX();
int pobierzY();
void ustawX(int wspX);
void ustawY(int wspY);
void ustawWspolrzedne(TPunkt punkt);
void ustawWspolrzedne(int wspX, int wspY);
};

class nazwa_klasy_potomnej : public nazwa_klasy_bazowej
{
public:
// definicja klasy potomnej
};

X.

Dziedziczenie



Dziedziczenie to jedna z podstawowych technik programowania obiektowego.
Dziedziczenie realizowane jest za pomocą symbolu : (dwukropek) , w następującej
konstrukcji







gdzie:

klasa potomna (klasa podrzędna, podklasa) to nowa klasa przejmująca
(dziedzicząca) składowe klasy bazowej,

klasa bazowa (klasa podstawowa, klasa nadrzędna, nadklasa) to klasa już
zdefiniowana, służąca jako pewien wzorzec dla nowej klasy potomnej.


Przykładem klasy bazowej może być definicja klasy TPunkt – reprezentująca punkt na
płaszczyźnie (plik punkt6.h).


















Plik punkt6.h.

Aby utworzyć reprezentację punktu w przestrzeni trójwymiarowej, należałoby stworzyć
definicję nowej klasy o nazwie TPunkt3D. Można ją tworzyć od nowa, by uwzględnić
trzy współrzędne x,y,z.


background image

40

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II.

______________________________________________________________________

______________________________________________________________________

©2006 Jerzy Kluczewski

class TPunkt3D : public TPunkt
{
public:
int z;
TPunkt3D();
~TPunkt3D();
int pobierzZ();
void ustawZ(int wspZ);
void ustawWspolrzedne(TPunkt3D punkt);
void ustawWspolrzedne(int wspZ);
};


Można wykorzystać fakt, że dla klasy TPunkt już zostały zdefiniowane odpowiednie
pola (x, y) oraz napisane odpowiednie metody obsługujące współrzędne (x,y) i dopisać
po prostu nowe pole z oraz metody obsługujące trzeci wymiar (Rys. 13).

Wybór tej drugiej metody nazywamy dziedziczeniem.

Następuje więc dziedziczenie gotowych rozwiązań z klasy bazowej TPunkt
(reprezentującej punkt na płaszczyźnie) do nowej klasy potomnej TPunkt3D.














Ciąg dalszy pliku punkt6.h.

W ten oto sposób programista nie namęczył się wiele, bowiem dopisał tylko:
pole z, oraz metody:

TPunkt3D()

~TPunkt3D()

pobierzZ()

ustawZ()

ustawWspolrzedne()


Aby przekonać się jak zachowują się obiekty klasy potomnej TPunkt3D wystarczy
napisać krótki program, demonstrujący technikę dziedziczenia – patrz program w pliku
punk6.cpp.

Wynik działania programu to:
Konstruktor TPunkt
Konstruktor TPunkt3D
Konstruktor TPunkt
Konstruktor TPunkt3D
10
20
30
0
0
0

background image

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II. 41
______________________________________________________________________

©2006 Jerzy Kluczewski

#include <iostream>
#include "Punkt6.h"
using namespace std;
//==== klasa bazowa ====
TPunkt::TPunkt()
{
cout<<"Konstruktor TPunkt"<< endl;
x = 0;
y = 0;
}
TPunkt ::~TPunkt()
{
}


Rys. 12. Dziedziczenie składowych klasy TPunkt, do klasy potomnej TPunkt3D.

Plik punk6.cpp















Klasa bazowa TPunkt














int x
int y
TPunkt()
~TPunkt()
pobierzX()
pobierzY()
ustawX()
ustawY()
ustawWspolrzedne()

Klasa potomna TPunkt3D















Składowe

dopisane

Składowe

dziedziczone

Nowe (dopisane):

int z;
TPunkt3D()
~TPunkt3D()
pobierzZ()
ustawZ()
ustawWspolrzedne()

background image

42

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II.

______________________________________________________________________

______________________________________________________________________

©2006 Jerzy Kluczewski

int TPunkt::pobierzX()
{
return x;
}
int TPunkt::pobierzY()
{
return y;
}
void TPunkt::ustawX(int wspX)
{
x = wspX;
}
void TPunkt::ustawY(int wspY)
{
y = wspY;
}
void TPunkt::ustawWspolrzedne(TPunkt punkt)
{
x = punkt.x;
y = punkt.y;
}
void TPunkt::ustawWspolrzedne(int wspX, int wspY)
{
x = wspX;
y = wspY;
}
//==== klasa potomna ====
TPunkt3D::TPunkt3D()
{
cout<<"Konstruktor TPunkt3D"<< endl;
z = 0;
}
TPunkt3D ::~TPunkt3D()
{
}
int TPunkt3D::pobierzZ()
{
return z;
}
void TPunkt3D::ustawZ(int wspZ)
{
z = wspZ;
}


Plik punk6.cpp – ciąg dalszy















































background image

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II. 43
______________________________________________________________________

©2006 Jerzy Kluczewski

void TPunkt3D::ustawWspolrzedne(TPunkt3D punkt)
{
z = punkt.z;
}
void TPunkt3D::ustawWspolrzedne(int wspZ)
{
z = wspZ;
}


int main()
{
TPunkt3D punkt1;
punkt1.ustawX(10);
punkt1.ustawY(20);
punkt1.ustawZ(30);
TPunkt3D punkt2;

cout << punkt1.x << endl;
cout << punkt1.y << endl;
cout << punkt1.z << endl;

cout << punkt2.x << endl;
cout << punkt2.y << endl;
cout << punkt2.z << endl;
system("pause");
return 0;
}


Plik punk6.cpp – ciąg dalszy
































Stosując dziedziczenie ważną kwestią jest zachowanie się konstruktorów klasy bazowej
i potomnej. Jeśli w klasie bazowej istnieje konstruktor, który można wywołać bez
parametrów (konstruktor domyślny TPunkt), to podczas tworzenia obiektów klasy
potomnej najpierw wykonywany jest konstruktor klasy bazowej a potem konstruktor
klasy potomnej (TPunkt3D).










background image

44

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II.

______________________________________________________________________

______________________________________________________________________

©2006 Jerzy Kluczewski

XI.

Dostęp do składowych klasy


W C++ programista może decydować o sposobie dostępu do składowych klasy. Do tego
celu służą modyfikatory dostępu (ang. access modifiers), zwane również
specyfikatorami. Każda składowa może być:

publiczna (public),

prywatna (private),

chroniona (protected).

Składowe publiczne


Dostęp do składowych publicznych jest nieograniczony, można się do nich odwoływać
bezpośrednio.

Składowe prywatne


Dostęp do składowych prywatnych jest ograniczony tylko i wyłącznie do metod
zdefiniowanych w danej klasie (oraz do funkcji zaprzyjaźnionych).

Składowe chronione


Dostęp do składowych chronione mają tylko metody zdefiniowane w danej klasie i
klasach pochodnych.

Jeśli nie zastosujemy żadnego modyfikatora, to składowe klasy zostaną potraktowane
tak, jakby wystąpił modyfikator private. Poniższe definicje klasy są równoważne:














Aby sprawdzić, czy do składowej prywatnej można się odwołać,
napisz program program1.cpp, który pokaże czy jest to możliwe.
Przy próbie kompilacji programu, kompilator wyświetli błąd

[C++ Error] E2247 ‘Bazowa::x’ is not accessible

class nazwa_klasy
{
// definicja wnętrza klasy
};

class nazwa_klasy
{
private:
// definicja wnętrza klasy
};

background image

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II. 45
______________________________________________________________________

©2006 Jerzy Kluczewski

Jeśli pole x jest prywatne, to instrukcja odwołująca się do niego jest błędna:
obiekt1.x = 100;
















program1.cpp

Jeśli do składowych prywatnych nie można się odwoływać bezpośrednio, to w jaki
sposób zmieniać ich wartości? Najlepszym sposobem na to jest dopisanie publicznych
metod operujących na składowych prywatnych. Umieść w klasie Bazowa metody getX
i setX. Pierwsza będzie zwracała wartość pola x. a druga będzie przypisywała polu x
wartość argumentu o nazwie x. Ilustruje to program program2.cpp.























program2.cpp

class Bazowa
{

private:

int x;

public:

int y;

};

int main()
{
Bazowa obiekt1;
obiekt1.x = 100;
obiekt1.y = 200;
};

#include <iostream>
using namespace std;
class Bazowa
{
private:

int x;

public:

int y;

int getX() { return x;};

void setX(int x)

{ this -> x = x; };

};
int main()
{
Bazowa obiekt1;
obiekt1.setX(100);
obiekt1.y = obiekt1.getX();
cout << obiekt1.getX() << endl;
cout << obiekt1.y << endl;
system("pause");
};

background image

46

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II.

______________________________________________________________________

______________________________________________________________________

©2006 Jerzy Kluczewski

XII.

Modyfikatory i dziedziczenie


Sprawdź teraz jak działają modyfikatory przy dziedziczeniu. W programie
program3.cpp definiujemy dwie klasy Bazowa i Pochodna (klasa Pochodna
dziedziczy z klasy Bazowa). W klasie bazowej zdefiniuj trzy składowe:
x – pole prywatne,
y – pole publiczne,
z – pole chronione.

W klasie pochodnej zdefiniuj sześć publicznych metod zajmujących się ustawianiem i
pobieraniem wartości poszczególnych pól. Następnie w funkcji main utwórz obiekt
klasy Pochodna oraz wywołaj jego metody setY i setZ, a na koniec sprawdź, czy
możliwe jest odwołanie się do pól y i z.
































program3.cpp

class Bazowa
{
private:

int x;

public:

int y;

protected:
int z;
};

class Pochodna: public Bazowa
{
public:
int getX() {return x; };
int getY() {return y; };
int getZ() {return z; };
void setX(int x) {this->x = x; };
void setY(int y) {this->y = y; };
void setZ(int z) {this->x = z; };
};

int main()
{
Pochodna obiekt1;
obiekt1.setY(100);
obiekt1.setZ(200);
obiekt1.y = obiekt1.z;
obiekt1.y = obiekt1.getZ();
};

background image

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II. 47
______________________________________________________________________

©2006 Jerzy Kluczewski


Przy próbie kompilacji programu program3.cpp, kompilator wyświetli błędy:
[C++ Error] E2247 ‘Bazowa::x’ is not accessible
[C++ Error] E2247 ‘Bazowa::z’ is not accessible

Nieprawidłowości w programie program3.cpp to:

Deklaracje:











są błędne, bo klasa pochodna nie ma dostępu do prywatnych składowych klasy
bazowej.

Instrukcja




jest błędna, ponieważ do pola chronionego nie można się odwoływać bezpośrednio.


UWAGA:
Przeczytaj uważnie tekst w ramce „Reguły budowania klas potomnych” (Rys. 13).

Praktyczny cel stosowania modyfikatorów


Modyfikatory private i protected pozwalają na ukrywanie wnętrza klasy (pola klasy), a
na zewnątrz udostępnienie tylko tzw. interfejsu klasy (metody publiczne). Ukrywanie
wnętrza obiektu (klasy) nazywamy hermetyzacją i jest to jedna z głównych cech
programowania obiektowego. Dla programisty korzystającego z gotowych klas
powinny być dostępne tylko metody operujące na polach (właściwościach) klasy
(obiektu). W ten sposób autor klas może w sposób niezauważalny zmieniać
reprezentację wewnętrzną klasy, a korzystający z niej nie musi się tymi zmianami
przejmować.





int getX() {return x; };

void setX(int x)
{
this->x = x;
};

obiekt1.y = obiekt1.z;

background image

48

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II.

______________________________________________________________________

______________________________________________________________________

©2006 Jerzy Kluczewski

Reguły budowania klas potomnych


Rys. 13. Reguły budowania klas potomnych.

class potomna : modyfikator klasa_bazowa
{
// definicja klasy potomnej
};

Schemat budowania klasy potomnej można ogólnie przedstawić jako:

Oznacza to, że klasa potomna ma wpływ na to, w jaki sposób będą
dziedziczone składowe klasy bazowej. Można zatem zmieniać reguły
dostępu. Jedynymi składowymi, których zachowania nie można zmienić, są
składowe prywatne. W dwóch pozostałych przypadkach obowiązują
następujące reguły:

1.

jeżeli przed nazwą klasy bazowej wystąpi modyfikator public, to w
klasie potomnej wszystkie składowe publiczne pozostają
publicznymi, a wszystkie składowe chronione pozostają chronione.

2.

jeżeli przed nazwą klasy bazowej wystąpi modyfikator private, to w
klasie potomnej wszystkie składowe (publiczne i chronione)
pozostają prywatnymi.

3.

jeżeli przed nazwą klasy bazowej wystąpi modyfikator protected, to
w klasie potomnej wszystkie składowe publiczne stają się
chronionymi, a i chronione pozostają chronionymi.

class Bazowa
{

private:

int x;

public:

int y;

protected:

int z;

};

class
Pochodna : private Bazowa
{
};

W przykładowej klasie

Pochodna wszystkie

składowe będą

prywatne i nie będzie

do nich

bezpośredniego

dostępu.

REGUŁY BUDOWANIA KLAS POTOMNYCH

background image

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II. 49
______________________________________________________________________

©2006 Jerzy Kluczewski


Zadanie XII-1


Napisz kod klasy bazowej TOsoba, której zadaniem będzie przechowywanie imion i
nazwisk osób. Pola imie i nazwisko powinny być typu char* , a pamięć niezbędna do
przechowywania danych ma być rezerwowana dynamicznie w konstruktorze podczas
tworzenia obiektu. Pamiętaj o konstruktorach zwykłych i kopiujących. Napisz klasę
pochodną TPracownik, dziedziczącej pola i konstruktory klasy TOsoba oraz
przechowującej w polu stanowisko (char* stanowisko) określające stanowisko
zajmowane przez pracownika. Dopisz odpowiednie konstruktory:

TPracownik(char* imie, char* nazwisko, char* stanowisko); //konstruktor
TPracownik(TPracownik &pracownik); //konstruktor kopiujący
~TPracownik(); // destruktor

XIII.

Przesłanianie składowych klasy



Podczas dziedziczenia cech klasy bazowej, klasa pochodna przejmuje składowe klasy
bazowej. Co się jednak stanie, gdy w klasie pochodnej zdefiniujemy składową o takiej
samej nazwie?




















Może spowoduje to konflikt nazw? Nie, kod taki będzie poprawny. W obiektach klasy
Pochodna będą znajdować się dwa pola (Bazowa::x) i (Pochodna::x).

#include <iostream>
using namespace std;

class Bazowa
{
public:
int x;
};

class Pochodna : public Bazowa
{
public:
int x;
};

background image

50

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II.

______________________________________________________________________

______________________________________________________________________

©2006 Jerzy Kluczewski


Odwołanie się do pola x bezpośrednie (np.

obiekt.x = 2;

) spowoduje przesłonięcie

pola z klasy bazowej Bazowa. Nie ma więc do niej bezpośredniego dostępu. Do tego
pola x, które jest dziedziczone z klasy bazowej Bazowa mamy dostęp poprzez operator
zakresu ::. (np.

obiekt.Bazowa::x = 1;

).


















XIV.

Prosta hierarchia klas



Dziedziczenie pozwala na budowanie hierarchii klas czyli na wyprowadzanie z jednej
klasy bazowej wielu klas pochodnych, np. z ogólnej klasy Pojazd mogłyby dziedziczyć
takie klasy, jak Rower, Pociąg, Samochód. W przykładzie pokazano prostą hierarchię
dziedziczenia klas A,B,C oraz zachowanie się ich konstruktorów.

















int main()
{
Pochodna obiekt;
obiekt.x = 2;
obiekt.Bazowa::x = 1;
cout << obiekt.x << endl;
cout << obiekt.Bazowa::x << endl;
system("pause");
return 0;
}

class A

class B

class C

background image

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II. 51
______________________________________________________________________

©2006 Jerzy Kluczewski


Przykładowy program klasy2Unit1.cpp















































#include <iostream>
using namespace std;

class A
{
public:
int x;
A() {cout<<"Konstruktor klasy A"<<endl;}
};

class B : public A
{
public:
int y;
B() {cout<<"Konstruktor klasy B"<<endl;}
};

class C : public B
{
public:
int z;
C() {cout<<"Konstruktor klasy C"<<endl;}
};

int main()
{
C obiekt;
obiekt.x = 10;
obiekt.y = 20;
obiekt.z = 30;
cout << obiekt.x << endl;
cout << obiekt.y << endl;
cout << obiekt.z << endl;
system("pause");
return 0;
}

background image

52

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II.

______________________________________________________________________

______________________________________________________________________

©2006 Jerzy Kluczewski



Instrukcja





spowoduje utworzenie obiektu klasy C, która jest pochodną w stosunku do klasy
nadrzędnej B, z kolei klasa B jest pochodną klasy bazowej A. Spowoduje to, że
automatycznie zostaną wywołane konstruktory domyślne (jeśli takie zostały
zdefiniowane):

Konstruktor klasy A
Konstruktor klasy B
Konstruktor klasy C





XV.

Literatura pomocnicza



A. Majczak. C++ Przykłady praktyczne. Wydawnictwo Mikom, Warszawa 2003.
J. Liberty. C++ dla każdego. Wydawnictwo Helion, Gliwice 2002.
K. Loudon. C++ Leksykon kieszonkowy. Wydawnictwo Helion, Gliwice 2003.
A. Stasiewicz. C++ Ćwiczenia praktyczne. Wydawnictwo Helion, Gliwice 2004.


















C obiekt;

background image

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II. 53
______________________________________________________________________

©2006 Jerzy Kluczewski

XVI.

Odpowiedzi do zadań


Zadanie VII-1


Zadanie1Unit1.cpp







































// Program Zadanie1Unit1.cpp
// Odpowiedź do Zadania VII-1
#include <iostream>
using namespace std;

class Example
{
public:
int* pole1;
Example()
{
pole1 = new int;
*pole1 = 0;
cout <<"Wywolanie konstruktora"<<endl;
}

~Example()
{
delete pole1;
cout <<"Wywolanie destruktora"<<endl;
}
};

int main()
{
Example example;
*(example.pole1) = 100;
cout << *(example.pole1) << endl;
system("pause");
return 0;
}

background image

54

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II.

______________________________________________________________________

______________________________________________________________________

©2006 Jerzy Kluczewski

Zadanie VII-2


Zadanie2Unit1.cpp












































// Program Zadanie2Unit1.cpp
// Odpowiedź do Zadania VII-2
#include <iostream>
using namespace std;

class Example
{
public:
int* pole1;
Example()
{
pole1 = new int;
*pole1 = 0;
cout <<"Wywolanie konstruktora"<<endl;
}

~Example()
{
delete pole1;
cout <<"Wywolanie destruktora"<<endl;
}
};

int main()
{
Example *example = new Example();
*(example->pole1) = 100;
cout << *(example->pole1) << endl;
delete example;
system("pause");
return 0;
}

background image

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II. 55
______________________________________________________________________

©2006 Jerzy Kluczewski

Zadanie VII-3


Zadanie3.h
















Zadanie3Unit1.cpp



























class TPunkt
{
public:
int *x;
int *y;
TPunkt(int x, int y);
~TPunkt();
int pobierzX();
int pobierzY();
void ustawX(int wspX);
void ustawY(int wspY);
void ustawWspolrzedne(TPunkt &punkt);
void ustawWspolrzedne(int wspX, int wspY);
};

#include <iostream>
#include "Zadanie3.h"
using namespace std;
TPunkt::TPunkt(int x = 0, int y = 0) {

this->x = new int(x);
this->y = new int(y);

}
TPunkt ::~TPunkt() {

delete x;
delete y;

}
int TPunkt::pobierzX() {

return *x;

}
int TPunkt::pobierzY() {

return *y;

}
void TPunkt::ustawX(int wspX) {

*x = wspX;

}
void TPunkt::ustawY(int wspY) {

*y = wspY;

}

background image

56

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II.

______________________________________________________________________

______________________________________________________________________

©2006 Jerzy Kluczewski




Zadanie3Unit1.cpp - ciąg dalszy






















Zadanie VII-4

Zadanie4.h



















class TKontener
{
public:
TKontener(int size);
~TKontener();
int* tab;
int size;
int get(int index);
int set(int index, int value);
};

void TPunkt::ustawWspolrzedne(TPunkt &punkt)
{
*x = *punkt.x;
*y = *punkt.y;
}
void TPunkt::ustawWspolrzedne(int wspX, int wspY)
{
*x = wspX;
*y = wspY;
}

int main()
{
TPunkt punkt(100, 200);
cout << punkt.pobierzX() << endl;
cout << punkt.pobierzY() << endl;
system("pause");
return 0;
}

background image

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II. 57
______________________________________________________________________

©2006 Jerzy Kluczewski



Zadanie4Unit1.cpp














































#include <iostream>
#include "Zadanie4.h"
using namespace std;
TKontener::TKontener(int size) {

tab = new int[size];
this->size = size;

}
TKontener::~TKontener() {

delete tab;

}
int TKontener::get(int index) {

if (index<0 || index > size-1)

return -1;

return tab[index];

}
int TKontener::set(int index, int value) {
if (index<0 || index > size-1)
{
int* newtab = new int[index*2];
for(int i=0; i< size; i++)
newtab[i] = tab[i];
delete tab;
tab = newtab;
size = index * 2;
}
tab[index] = value;
return 0;
}

int main()
{
TKontener kontener(5);
for (int i=0; i < 5; i++)

kontener.set(i,10);

kontener.set(7,1);
kontener.set(8,2);
for (int i=0; i < 9; i++)

cout << kontener.get(i) << endl;

system("pause");
return 0;
}

background image

58

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II.

______________________________________________________________________

______________________________________________________________________

©2006 Jerzy Kluczewski

Zadanie IX-1

Zadanie5Unit1.h













Zadanie5Unit1.cpp































class TOsoba
{
public:
char* imie;
char* nazwisko;

TOsoba(char* imie, char* nazwisko); //konstruktor
TOsoba(TOsoba &osoba); //konstruktor kopiujący
~TOsoba(); // destruktor
};

#include <iostream>
#include "Zadanie5Unit1.h"
using namespace std;

TOsoba::TOsoba(char* imie, char* nazwisko)
{
int dlugosc = strlen(imie);
this->imie = new char[dlugosc+1];
strcpy(this->imie, imie);
dlugosc = strlen(nazwisko);
this->nazwisko = new char[dlugosc+1];
strcpy(this->nazwisko, nazwisko);
}

TOsoba::TOsoba(TOsoba &osoba)
{
int dlugosc = strlen(osoba.imie);
this->imie = new char[dlugosc+1];
strcpy(this->imie, osoba.imie);
dlugosc = strlen(osoba.nazwisko);
this->nazwisko = new char[dlugosc+1];
strcpy(this->nazwisko, osoba.nazwisko);
}

TOsoba::~TOsoba()
{
delete this->imie;
delete this->nazwisko;
}

background image

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II. 59
______________________________________________________________________

©2006 Jerzy Kluczewski


















Zadanie IX-2

Zadanie6Unit1.h














Zadanie6Unit1.cpp














int main()
{
TOsoba osoba1("Adam", "Abacki");
cout<<"Dane obiektu osoba1:"<<endl;
cout<<osoba1.imie<<" "<<osoba1.nazwisko<<endl;
TOsoba osoba2(osoba1);
cout<<"Dane obiektu osoba2:"<<endl;
cout<<osoba2.imie<<" "<<osoba2.nazwisko<<endl;
system("pause");
return 0;
}

class TNapis
{
public:
char* dane;

TNapis(); //konstruktor
int Dlugosc(void);
TNapis(char* tekst); //konstruktor
TNapis(TNapis &napis); //konstruktor kopiujący
~TNapis(); // destruktor
};

#include <iostream>
#include "Zadanie6Unit1.h"
using namespace std;

TNapis::TNapis()
{
dane = new char[1];
dane[0] = '\0';
}

background image

60

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II.

______________________________________________________________________

______________________________________________________________________

©2006 Jerzy Kluczewski


















































int TNapis::Dlugosc(void)
{
return strlen(this->dane);
}

TNapis::TNapis(char* tekst)
{
int rozmiar = strlen(tekst) + 1;
dane = new char[rozmiar];
strcpy(this->dane, tekst);
}
TNapis::TNapis(TNapis &napis)
{
dane = new char[napis.Dlugosc()+1];
strcpy(this->dane,napis.dane);
}
TNapis::~TNapis()
{
delete this->dane;
}

int main()
{
TNapis s1;
TNapis s2("ABC");
TNapis s3(s2);
cout<<"Napis "<<s1.dane<< " ma dlugosc "<<s1.Dlugosc()<<endl;
cout<<"Napis "<<s2.dane<< " ma dlugosc "<<s2.Dlugosc()<<endl;
cout<<"Napis "<<s3.dane<< " ma dlugosc "<<s3.Dlugosc()<<endl;
system("pause");
return 0;
}

background image

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II. 61
______________________________________________________________________

©2006 Jerzy Kluczewski

Zadanie IX-3

Zadanie7Unit1.h












Zadanie7Unit1.cpp
































class TKlasa
{
public:
static int count;

TKlasa(); //konstruktor
~TKlasa(); // destruktor
};

#include <iostream>
#include "Zadanie7Unit1.h"
using namespace std;

int TKlasa::count = 0;

TKlasa::TKlasa()
{
count++;
}
TKlasa::~TKlasa()
{
count– –;
}

background image

62

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II.

______________________________________________________________________

______________________________________________________________________

©2006 Jerzy Kluczewski


Zadanie XII-1

PracownikUnit1.h



























PracownikUnit1.cpp
















//klasa bazowa
class TOsoba
{
public:
char* imie;
char* nazwisko;

TOsoba(); //konstruktor domyslny
TOsoba(char* imie, char* nazwisko); //konstruktor
TOsoba(TOsoba &osoba); //konstruktor kopiujący
~TOsoba(); // destruktor
};

//klasa pochodna
class TPracownik : public TOsoba
{
public:
char* stanowisko;

TPracownik(char* imie, char* nazwisko, char* stanowisko);
//konstruktor
TPracownik(TPracownik &pracownik); //konstruktor kopiujący
~TPracownik(); // destruktor
};

#include <iostream>
#include "PracownikUnit1.h"
using namespace std;

//klasa bazowa
TOsoba::TOsoba()
{
cout << "Konstruktor domyslny TOsoba" << endl;
this->imie = new char[1];
strcpy(this->imie, "");
this->nazwisko = new char[1];
strcpy(this->nazwisko, "");
}

background image

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II. 63
______________________________________________________________________

©2006 Jerzy Kluczewski



PracownikUnit1.cpp – ciąg dalszy














































TOsoba::TOsoba(char* imie, char* nazwisko)
{
int dlugosc = strlen(imie);
this->imie = new char[dlugosc+1];
strcpy(this->imie, imie);
dlugosc = strlen(nazwisko);
this->nazwisko = new char[dlugosc+1];
strcpy(this->nazwisko, nazwisko);
}

TOsoba::TOsoba(TOsoba &osoba)
{
int dlugosc = strlen(osoba.imie);
this->imie = new char[dlugosc+1];
strcpy(this->imie, osoba.imie);
dlugosc = strlen(osoba.nazwisko);
this->nazwisko = new char[dlugosc+1];
strcpy(this->nazwisko, osoba.nazwisko);
}

TOsoba::~TOsoba()
{
cout << "Destruktor TOsoba"<<endl;
delete this->imie;
delete this->nazwisko;
}

//klasa pochodna
TPracownik::TPracownik(char* imie, char* nazwisko, char* stanowisko)
{
strcpy(this->imie, imie);
strcpy(this->nazwisko, nazwisko);

int dlugosc = strlen(stanowisko);
this->stanowisko = new char[dlugosc+1];
strcpy(this->stanowisko, stanowisko);
}

TPracownik::TPracownik(TPracownik &pracownik)
{
int dlugosc = strlen(pracownik.stanowisko);
this->stanowisko = new char[dlugosc+1];
strcpy(this->stanowisko, pracownik.stanowisko);
}

background image

64

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II.

______________________________________________________________________

______________________________________________________________________

©2006 Jerzy Kluczewski


PracownikUnit1.cpp – ciąg dalszy
















































TPracownik::~TPracownik()
{
cout << "Destruktor TPracownik"<<endl;
delete this->stanowisko;
}

int main()
{
TPracownik pracownik1("Barnaba", "Celinowski", "Kierownik");
cout<<"Dane obiektu pracownik1:"<<endl;
cout<<pracownik1.imie<<endl;
cout<<pracownik1.nazwisko<<endl;
cout<<pracownik1.stanowisko<<endl;
system("pause");
return 0;
}

background image

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II. 65
______________________________________________________________________

©2006 Jerzy Kluczewski

SPIS TREŚCI


I.

Przestrzenie nazw ..................................................................................................... 2

Przestrzeń nazw std....................................................................................................... 5

II. Obiekty...................................................................................................................... 6

Projekt obiektu .............................................................................................................. 6

III.

Klasa ..................................................................................................................... 7

Klasa TPunkt................................................................................................................. 8
Pola klasy...................................................................................................................... 8
Metody klasy................................................................................................................. 8
Określenie struktury klasy ............................................................................................ 8
Odwołania do składowych obiektu............................................................................. 11
Wiele obiektów tej samej klasy .................................................................................. 11

IV.

Właściwości obiektu ........................................................................................... 12

Argumenty metod ....................................................................................................... 12
Odwołanie this ............................................................................................................ 14

V. Przeciążanie metod ................................................................................................. 15

Obiekt jako argument.................................................................................................. 15
Overloading ................................................................................................................ 17

VI.

Sposoby przekazywania argumentów................................................................. 19

VII.

Dynamiczne obiekty ........................................................................................... 21

Inicjalizacja pól........................................................................................................... 22
Konstruktor ................................................................................................................. 23
Destruktor ................................................................................................................... 24

Zadanie VII-1.......................................................................................................... 25
Zadanie VII-2.......................................................................................................... 25
Zadanie VII-3.......................................................................................................... 26
Zadanie VII-4.......................................................................................................... 26

VIII. Konstruktory ....................................................................................................... 26

Argumenty konstruktorów.......................................................................................... 26
Konstruktor kopiujący ................................................................................................ 28
Konstruktor kopiujący i pola wskaźnikowe................................................................ 29

Zadanie VIII-1 ........................................................................................................ 29

IX.

Składowe statyczne............................................................................................. 33

Pola statyczne ............................................................................................................. 33
Metody statyczne ........................................................................................................ 35
Dostęp do pól i metod ................................................................................................. 35
Dostęp do pól i metod – c.d. ....................................................................................... 37

Zadanie IX-1 ........................................................................................................... 38
Zadanie IX-2 ........................................................................................................... 38
Zadanie IX-3 ........................................................................................................... 38

X. Dziedziczenie.......................................................................................................... 39
XI.

Dostęp do składowych klasy............................................................................... 44

Składowe publiczne .................................................................................................... 44
Składowe prywatne..................................................................................................... 44
Składowe chronione.................................................................................................... 44

XII.

Modyfikatory i dziedziczenie ............................................................................. 46

Praktyczny cel stosowania modyfikatorów ............................................................ 47
Reguły budowania klas potomnych ........................................................................ 48
Zadanie XII-1.......................................................................................................... 49

background image

66

C++. Programowanie obiektowe. Ćwiczenia podstawowe. Cz. II.

______________________________________________________________________

______________________________________________________________________

©2006 Jerzy Kluczewski

XIII. Przesłanianie składowych klasy.......................................................................... 49
XIV.

Prosta hierarchia klas ...................................................................................... 50

XV.

Literatura pomocnicza ........................................................................................ 52

XVI.

Odpowiedzi do zadań...................................................................................... 53

Zadanie VII-1.......................................................................................................... 53
Zadanie VII-2.......................................................................................................... 54
Zadanie VII-3.......................................................................................................... 55
Zadanie VII-4.......................................................................................................... 56
Zadanie IX-1 ........................................................................................................... 58
Zadanie IX-2 ........................................................................................................... 59
Zadanie IX-3 ........................................................................................................... 61
Zadanie XII-1.......................................................................................................... 62


Wyszukiwarka

Podobne podstrony:
Program cwiczen z podstaw konst Nieznany
gri2 lab cwiczenia z podstaw pr Nieznany
cpp cwiczenia podstawowe 1 Kluczewski
cwiczenie 8 Podstawy diagnostyk Nieznany
Cwiczenia Access Podstawy 3 id Nieznany
Cwiczenia 1 podstawy edycji id Nieznany
cwiczenia 4 podstawczaki id 124 Nieznany (2)
cwiczenie9 id 125928 Nieznany
matematyka podstawowe wzory i Nieznany
cwiczenia23 id 124959 Nieznany
cwiczenia 4 2 id 124428 Nieznany
Fizjologia Cwiczenia 3 id 17436 Nieznany

więcej podobnych podstron