Podstawy
programowania
obiektowego
Ćwiczenia laboratoryjne nr 2
Temat: Konstruktory, destruktory, funkcje zaprzyjaźnione
Prowadzący:
mgr inż. Dariusz Rataj
Koszalin 2001
Podstawy programowania obiektowego ćw nr 2
Strona 2
Spis treści:
1. Konstruktor przeciążony, destruktor obiektu
2. Hermetyzacja - ukrywanie informacji
1. Konstruktor przeciążony, destruktor obiektu
Dla każdej klasy mamy możliwość utworzenia kilku konstruktorów. Może to być konstruktor
bezparametrowy i konstruktor z parametrami. Jeżeli klasa nie posiada zdefiniowanego
konstruktora to kompilator automatycznie doda konstruktor bezparametrowy. Możemy
także samodzielnie zdefiniować działanie konstruktora bezparametrowego. Przykład 1
definiuje klasę Plik otwierającą plik dyskowy do zapisu. Zdefiniowany został konstruktor
bezparametrowy - tworzący plik o nazwie wbudowanej (default.txt) oraz konstruktor
z parametrem - nazwą pliku dyskowego.
Deklaracja zmiennej obiektowej
Plik plik1(
"proba.txt"
);
// konstruktor z parametrem - nazwa pliku
wywoła konstruktor z parametrem i utworzy plik dyskowy o nazwie proba.txt.
Deklaracja zmiennej obiektowej
Plik plik2;
// konstruktor bezparametrowy - plik default.txt
wywoła konstruktor bezparametrowy i utworzy plik dyskowy o nazwie wbudowanej
default.txt.
Kompilator automatycznie decyduje jaki konstruktor ma być wywołany w zależności od typu
parametrów w deklaracji obiektu.
Konstruktory w przykładzie 1 wykonują operację otwarcia pliku dyskowego. W takiej
sytuacji programista ma obowiązek zadbać o to aby plik ten został zamknięty przed
zakończeniem programu. Operację tą wykonuje destruktor (~Plik). Destruktor jest
wywoływany automatycznie w sytuacji gdy obiekt jest zwalniany (kończy się czas życia
obiektu - w tym przykładzie kończy się program). Dzięki zastosowaniu destruktora
programista nie musi pamiętać (zdarza się zapomnieć:-) o zamknięciu pliku przed
zakończeniem programu. Destruktor powinien również zwalniać pamięć rezerwowaną
dynamicznie w czasie działania programu, zamykać połączenia sieciowe itp.
Przykład 1. Definicja klasy Plik, utworzenie dwóch plików dyskowych
#include <stdio.h>
class
Plik
{
private
:
FILE* plik;
// zmienna plikowa
Public
:
Plik();
// konstruktor bezparametrowy
Plik(
char
*NazwaPliku);
// konstruktor z parametrem - nazwa pliku
~Plik();
// destruktor
void
zapisz(
char
*line);
// metoda zapisujaca linie tekstu do pliku
};
// konstruktor tworzy plik o nazwie wbudowanej default.txt
Plik::Plik()
{
if
((plik = fopen(
"default.txt"
,
"wt"
)) ==
NULL
)
{
fprintf(stderr,
"Nie moge otworzyc pliku!!!.\n"
);
}
}
Podstawy programowania obiektowego
Strona 3
// konstruktor tworzy plik o nazwie podanej jako parametr
Plik::Plik(
char
*NazwaPliku)
{
if
((plik = fopen(NazwaPliku,
"wt"
)) ==
NULL
)
{
fprintf(stderr,
"Nie moge otworzyc pliku!!!.\n"
);
}
}
void
Plik::zapisz(
char
*text)
{
fprintf(plik, text);
// zapis lini do pliku
fprintf(plik,
"\n"
);
// przejscie do nastepnej linii
printf(
"Zapisano do pliku: %s\n\r"
, text);
}
// destruktor zamyka plik
Plik::~Plik()
{
if
(plik) fclose(plik);
}
void
main()
{
Plik plik1(
"proba.txt"
);
// konstruktor z parametrem - nazwa pliku
Plik plik2;
// konstruktor bezparametrowy - plik default.txt
plik1.zapisz(
"--------- plik proba.txt ------------"
);
// zapis do 1 pliku
plik1.zapisz(
"proba zapisu tekstu"
);
plik1.zapisz(
"---------- koniec zapisu -------------"
);
plik2.zapisz(
"--------- plik default.txt ----------"
);
// zapis do 2 pliku
plik2.zapisz(
"proba zapisu tekstu"
);
plik2.zapisz(
"---------- koniec zapisu -------------"
);
}
2. Hermetyzacja - ukrywanie informacji
Projektant-programista ma możliwość ukrycia najbardziej niepewnych części projektu
i przez to zmniejszenia niebezpieczeństwa ewentualnych przeróbek (zmniejszenia wpływu
na pozostałe moduły projektu). W systemach obiektowych przyjęto formalny podział praw
dostępu do interfejsu (warstwy zewnętrznej):
•
obszar publiczny (public) widzialny dla wszystkich innych elementów projektu,
•
obszar chroniony (protected) widzialny tylko dla podklas danej klasy (niewidzialny
dla innych klas i funkcji),
•
obszar prywatny (private) widzialny dla danej klasy i klas, funkcji
zaprzyjaźnionych.
Możemy dopuścić funkcję do obszaru prywatnego klasy przez deklarację klasy jako funkcję
zaprzyjaźnioną. Funkcja zaprzyjaźniona nie jest funkcją składową klasy. W przykładzie 2
zdefiniowane zostały dwie funkcje zaprzyjaźnione: odejmij i porownaj.
Przykład 2. Definicja klasy zespolona, demonstracja działań na liczbach zespolonych
#include <iostream.h>
// cin, cout
#include <math.h>
// fabs, sqrt
#include <conio.h>
#define TRUE
1
#define FALSE
0
// deklaracja klasy (interfejs klasy)
class
zespolona
{
Podstawy programowania obiektowego ćw nr 2
Strona 4
public
:
zespolona();
// konstruktor
zespolona(
double
r,
double
i =
0
);
// konstruktor
void
ustaw(
double
r,
double
i);
// ustawienie wartosci
void
drukuj();
void
czytaj();
double
modul();
double
rzecz() {
return
re; }
double
uroj() {
return
im; }
zespolona sprzez();
zespolona dodaj(zespolona z);
// funkcje zaprzyjaznione z klasa
friend zespolona odejmij(zespolona z1, zespolona z2);
friend
int
porownaj(zespolona z1, zespolona z2);
// pola prywatne
private
:
double
re, im;
};
// definicja metod
zespolona::zespolona()
{
re =
0
; im =
0
;
}
zespolona::zespolona(
double
r,
double
i)
{
re = r; im = i;
}
void
zespolona::ustaw(
double
r,
double
i)
{
re = r; im = i;
}
void
zespolona::drukuj()
{
cout <<
'('
<< re <<
", "
<< im <<
')'
;
}
void
zespolona::czytaj()
{
cout <<
"re = "
; cin >> re;
cout <<
"im = "
; cin >> im;
}
double
zespolona::modul()
{
return
(sqrt(re*re+im*im));
}
zespolona zespolona::sprzez()
{
return
zespolona(re, -im);
}
zespolona zespolona::dodaj(zespolona z)
{
return
zespolona(re+z.re, im+z.im);
}
// funkcje zaprzyjaznione odejmij i porownaj
zespolona odejmij(zespolona z1, zespolona z2)
{
return
zespolona(z1.re-z2.re, z1.im-z2.im);
}
int
porownaj(zespolona z1, zespolona z2)
{
if
( fabs(z1.re-z2.re) <
1e-10
&& fabs(z1.im-z2.im) <
1e-10
)
return
TRUE;
else
return
FALSE;
}
Podstawy programowania obiektowego
Strona 5
int
main()
{
zespolona z1, z2, z3(
1
), z4(
2
,
3
);
zespolona z5 = z4;
// inicjalizacja
clrscr();
cout <<
"z1 = "
; z1.drukuj(); cout <<
"\tz1"
<< endl;
cout <<
"z2 = "
; z2.drukuj(); cout <<
"\tz2"
<< endl;
cout <<
"z3 = "
; z3.drukuj(); cout <<
"\tz3(1)"
<< endl;
cout <<
"z4 = "
; z4.drukuj(); cout <<
"\tz4(2, 3)"
<< endl;
cout <<
"z5 = "
; z5.drukuj(); cout <<
"\tz5 = z4"
<< endl << endl;
z1.czytaj();
z2.ustaw(
3
, -
4
);
z3 = z1.sprzez();
z4 = z1.dodaj(z2);
z5 = odejmij(z1, z2);
cout <<
"z1 = "
; z1.drukuj(); cout <<
"\tz klawiatury"
<< endl;
cout <<
"z2 = "
; z2.drukuj(); cout <<
"\tustaw(3, -4)"
<< endl;
cout <<
"z3 = "
; z3.drukuj(); cout <<
"\tsprzezona do z1"
<< endl;
cout <<
"z4 = "
; z4.drukuj(); cout <<
"\tz1 + z2"
<< endl;
cout <<
"z5 = "
; z5.drukuj(); cout <<
"\tz1 - z2"
<< endl << endl;
z1 = z2;
// podstawienie
cout <<
"z1 = "
; z1.drukuj(); cout <<
"\tz1 = z2"
<< endl;
cout <<
"Re(z1) = "
<< z1.rzecz() << endl;
cout <<
"Im(z1) = "
<< z1.uroj() << endl;
cout <<
"|z1| = "
<< z1.modul() << endl << endl;
if
( porownaj(z1, z2) == TRUE )
cout <<
"z1 jest rowne z2"
<< endl;
else
cout <<
"z1 jest rozne od z2"
<< endl;
cout << endl <<
"Nacisnij dowolny klawisz..."
;
getch();
return
0
;
}
Zadania do wykonania na zajęciach i w domu:
1. Zdefiniuj klasę pilka. Klasa powinna zawierać:
•
Pole prywatne a typu całkowitego - promień koła.
•
Pole prywatne kolor typu całkowitego - kolor koła.
•
Konstruktor bezparametrowy inicjujący wartości początkowe pól (wybrać dowolne).
•
Konstruktor z parametrami promień i kolor.
•
Metodę publiczną powierzchnia - obliczającą pole powierzchni koła.
•
Metodę publiczną ustawPromien - zmieniającą promien koła.
•
Metodę publiczną ustawKolor - zmieniającą kolor koła.
Zdefiniuj funkcję zaprzyjaźnioną porownaj - porównującą czy dwa koła mają takie same
powierzchnie i kolor.
2. Zdefiniuj klasę prostokat. Klasa powinna zawierać:
•
Pola prywatne a, b typu całkowitego - dlugość boków prostokąta.
•
Konstruktor bezparametrowy inicjujący wartości początkowe pól (wybrać dowolne).
•
Konstruktor z parametrami długość i wysokość prostokąta.
•
Metodę publiczną powierzchnia - obliczającą pole powierzchni prostokąta.
•
Metodę publiczną dajDlugosc - zwracającą długość prostakąta.
•
Metodę publiczną dajWysokosc - zwracającą wysokość prostakąta.
Zdefiniuj funkcję zaprzyjaźnioną jestKwadrat - porównującą boki prostokąta (czy jest kwadratem).
3. Zdefiniuj klasę punkt. Klasa powinna zawierać:
•
Pola prywatne x, y typu całkowitego - współrzędne punktu.
•
Konstruktor bezparametrowy inicjujący wartości początkowe pól (wybrać dowolne).
•
Konstruktor z parametrami: współrzędne punktu.
•
Metodę publiczną dajX - zwracającą wsp. x.
•
Metodę publiczną dajY - zwracającą wsp. y.
Zdefiniuj funkcję zaprzyjaźnioną porównaj - porównującą współrzędne dwóch punktów (czy punkty
się nakładają).