int

Transkrypt

int
www.imio.polsl.pl
JĘZYKI PROGRAMOWANIA
Z
PROGRAMOWANIEM OBIEKTOWYM
Wykład 13
1
KLASY A ZASŁANIANIE NAZW
www.imio.polsl.pl
Nazwy danych składowych i funkcji składowych mają zakres klasy, więc w obrębie
klasy zasłaniają takie same nazwy spoza klasy.
Przykład (wersja 1):
#include <iostream>
using namespace std;
//-----------------------------------------------------------------------------
int dana=5;
// dana (zmienna) globalna
//-----------------------------------------------------------------------------
class Obliczenia
{public:
int dana;
// dana lokalna klasy (nazwa jak dana globalna)
int oddaj_1() {return dana;}
// odniesienie się do danej lokalnej
int oddaj_2() {return ::dana;}
// odniesienie się do danej globalnej
// ...
// ciąg dalszy ciała klasy
};
//-----------------------------------------------------------------------------
int main()
{
Obliczenia obiekt;
obiekt.dana=777;
cout<<obiekt.oddaj_1()<<endl;
cout<<obiekt.oddaj_2()<<endl;
return 0;
}
// tworzymy obiekt
// wpisujemy do danej obiektu
// wywołania funkcji
2
KLASY A ZASŁANIANIE NAZW
www.imio.polsl.pl
Przykład z poprzedniego slajdu jest poprawny, lecz...
o Klasy należy konstruować tak, by były „samowystarczalne”.
o Jeśli klasa ma korzystać ze zmiennej globalnej – należy przesłać ją do klasy jako
argument stosownej funkcji składowej:
void Klasa::odbior(int te)
{
zmienna=te;
}
Podsumowując: nie należy z wnętrza klasy odwoływać się do zmiennych globalnych w
programie
(szczególnie jeśli będziemy chcieli klasę wykorzystać w innym projekcje
lub np. komuś udostępnić).
3
KLASY A ZASŁANIANIE NAZW
www.imio.polsl.pl
Przykład (wersja 2):
#include <iostream>
using namespace std;
//----------------------------------------------------------------------------int dana=5;
// obiekt globalny
//----------------------------------------------------------------------------class Obliczenia
// samowystarczalna klasa...
{public:
int dana, dana_odebrana;
void odbierz(int a) {dana_odebrana=a;} // nowa funkcja „do odbierania”
int oddaj_1() {return dana;}
// odniesienie się do danej lokalnej
int oddaj_2() {return dana_odebrana;} // odniesienie się do odebranej danej
};
//----------------------------------------------------------------------------int main()
Obliczenia obiekt;
// tworzymy obiekt
{
obiekt.dana=777;
// wpisujemy do danej obiektu
obiekt.odbierz(dana);
// dana globalna jako argument
cout<<obiekt.oddaj_1()<<endl;
cout<<obiekt.oddaj_2()<<endl;
return 0;
}
// wywołania funkcji
4
DZIEDZICZENIE
www.imio.polsl.pl
Dziedziczenie – technika obiektowa, pozwalająca tworzyć nowe klasy na podstawie
już istniejących klas.
„Dziedziczenie jest jedną z najwspanialszych cech obiektowo orientowanych języków
programowania” – J. Grębosz, Symfonia C++ standard.
Po co?
1. Oszczędność czasu.
o
Załóżmy, że istnieje jakaś klasa, która nie spełnia wszystkich oczekiwań.
o
Można ją poprzez dziedziczenie dopasować do naszych potrzeb tworząc na jej bazie
tzw. klasę pochodną.
o
Np.: mając klasę Telewizor_LCD można na jej podstawie stworzyć klasę
Telewizor_LCD_3D.
o
Ważne – nie musimy znać kodu źródłowego klasy podstawowej (a tylko jej definicję
w pliku .h) – możemy korzystać z klas napisanych przez kogoś innego...
5
www.imio.polsl.pl
DZIEDZICZENIE
2. Tworzenie hierarchii klas.
o
Często klasy są w pewnej logicznej zależności i tworzą „naturalną” hierarchię.
o
Np.:
Srodek_transportu
Pojazd
Samochod
Rower
Statek
Samolot
...
o
Zamiast osobnych klas mamy sytuację: jakaś klasa jest szczególnym rodzajem innej
klasy,
o
np. Samochod i Rower są rodzajami czegoś, co nazwaliśmy Pojazd.
6
DZIEDZICZENIE
o
Inne przykłady:
- zarówno Prostokat , Trapez jak i Romb to specyficzny Czworokat,
- Lew i Mysz są to zwierzęta należące do gromady (tu: klasy) Ssak, itd.
o
Proces dziedziczenia pozwala w takim przypadku na wprowadzenie relacji
między poszczególnymi klasami.
www.imio.polsl.pl
Dziedziczenie pozwala na wykorzystanie tego, co istniejąca klasa posiada
i dostosowanie jej do innych potrzeb:
o dodanie nowych danych składowych i funkcji składowych;
o stworzenie nowych wariantów funkcji składowych lub ew. danych składowych.
Jeżeli w klasie podstawowej i w klasie pochodnej są składniki (dane lub funkcje)
o tych samych nazwach, to w zakresie klasy pochodnej składnik z tej klasy zasłania
składnik odziedziczony.
7
DZIEDZICZENIE
www.imio.polsl.pl
Np.: mając klasę Pralka z poprzedniego wykładu:
class Pralka
// definicja klasy
{
int nr_programu;
int temperatura_prania;
public:
void pranie(int program, int temperatura);
void plukanie();
};
moglibyśmy chcieć stworzyć (postęp techniczny!) klasę Lepsza_Pralka,
która posiada nową daną składową (dla uproszczenia np. tylko godzina):
int o_ktorej_zaczac;
oraz zmodyfikowaną funkcję:
void pranie(int program, int temperatura, bool niski_poziom=false);
8
DZIEDZICZENIE
www.imio.polsl.pl
Realizacja:
class Lepsza_Pralka : public Pralka
// lista pochodzenia
{
int o_ktorej_zaczac;
public:
void pranie(int program, int temperatura, bool niski_poziom);
};
o
Klasa Pralka jest w tym przypadku klasą podstawową dla klasy Lepsza_Pralka.
o
Klasa Lepsza_Pralka jest w tym przypadku klasą pochodną klasy Pralka.
o
Nowa wersja funkcji składowej pranie „zastępuje” (zasłania) wersję funkcji pranie
z klasy podstawowej.
o
Wyrażenie po dwukropku to lista pochodzenia.
o
Specyfikator public przy liście pochodzenia – o tym nieco później...
9
DZIEDZICZENIE
o
www.imio.polsl.pl
Stwórzmy obiekt moja_nowa_pralka klasy Lepsza_Pralka:
Lepsza_pralka moja_nowa_pralka;
o
Wywołanie funkcji pranie dla obiektu klasy Lepsza_Pralka uruchamia funkcję
klasy pochodnej:
moja_nowa_pralka.pranie(7,40,1);
moja_nowa_pralka.pranie(7,40); //ostatni argument domyślny
o
Gdybyśmy chcieli wywołać funkcję pranie z klasy podstawowej, to należy
skorzystać z kwalifikatora zakresu ::
moja_nowa_pralka.Pralka::pranie(7,40);
o
Należy pamiętać definiując obiekt klasy pochodnej, że wewnątrz znajduje się
fragment odziedziczony po klasie podstawowej...
10
www.imio.polsl.pl
DZIEDZICZENIE
Przykład (publiczne dane składowe):
#include <iostream>
using namespace std;
class Punkt2D
{ public:
float x, y;
void wypisz1() { cout<<x<<" "<<y;}
};
// klasa podstawowa
// dane publiczne
// funkcja publiczna
//------------------------------------------------------------------
class Punkt3D: public Punkt2D
//
{ public:
float z;
void wypisz2() { cout<<x<<" "<<y<<" "<<z;}
};
klasa pochodna
//------------------------------------------------------------------
int main()
{
Punkt2D p2D;
p2D.x=1.1; p2D.y=2.2;
p2D.wypisz1(); cout<<endl;
// tworzymy obiekt klasy Punkt2D
// mamy dostęp do danych...
Punkt3D p3D;
p3D.x=5.5; p3D.y=6.6; p3D.z=7.7;
p3D.wypisz2(); cout<<endl;
// tworzymy obiekt klasy Punkt3D
p3D.Punkt2D::wypisz1();
cout<<endl;
//wywołanie f. klasy podstawowej
return 0;}
11
www.imio.polsl.pl
DZIEDZICZENIE
Przykład (prywatne dane składowe):
#include <iostream>
using namespace std;
class Punkt2D
{ float x, y;
public:
Punkt2D(float a, float b)
{x=a; y=b;}
void wypisz1()
{cout<<x<<" "<<y;}
};
// klasa podstawowa
// prywatne dane
// konstruktor
// publiczna funkcja
//------------------------------------------------------------------
class Punkt3D: public Punkt2D
// klasa pochodna
{ float z;
// prywatna dana
public:
Punkt3D(float a, float b, float c): Punkt2D(a,b)// konstruktor (o tym później)
{z=c;}
void wypisz2()
{Punkt2D::wypisz1(); //korzystamy z funkcji z klasy podstawowej
cout<<" "<<z;}
};
//------------------------------------------------------------------
int main()
{
Punkt2D p2D (1.1, 2.2);
p2D.wypisz1(); cout<<endl;
Punkt3D p3D(5.5,6.6,7.7);
p3D.wypisz2(); cout<<endl;
return 0;}
// tworzymy obiekt klasy Punkt2D
// tworzymy obiekt klasy Punkt3D
12
DZIEDZICZENIE
www.imio.polsl.pl
Dane składowe często nie są publiczne. Co wtedy z ewentualnymi klasami
pochodnymi?
Mogą istnieć funkcje dostępowe (jak w poprzednim przykładzie). Można jednak
inaczej...
Jak to jest z etykietą protected, czyli: rozwiązanie zagadki, po co ona jest...
o Etykieta ta została wprowadzona w właśnie na potrzeby dziedziczenia.
o Składniki za taką etykietą:
-
są dostępne dla klas pochodnych (jak gdyby były public);
dla „całego świata” są niedostępne, (jak gdyby były private).
13
www.imio.polsl.pl
DZIEDZICZENIE
Np.:
class Radio
{
string obudowa;
int zakres;
protected:
float dlugosc_fali;
void aut_strojenie();
public:
void glosnosc(int vol);
};
o
// definicja klasy
// składniki prywatne
// składniki dostępne dla klas pochodnych
// składniki dostępne dla każdego
Klasa podstawowa określa odpowiednimi etykietami, które ze składników:
- są dostępne tylko dla niej (private);
- chce udostępniać tylko klasom pochodnym (protected);
- chce, by były ogólnodostępne (public).
14
www.imio.polsl.pl
DZIEDZICZENIE
Przykład (dane składowe protected):
#include <iostream>
using namespace std;
class Punkt2D
// klasa podstawowa
{protectec:
float x, y;
// dane protected
public:
Punkt2D(float a, float b) {x=a; y=b;} // konstruktor
void wypisz1() {cout<<x<<" "<<y;}
// publiczna funkcja
};
//------------------------------------------------------------------
class Punkt3D: public Punkt2D
// klasa pochodna
{protectec:
float z;
// dana protected
public:
Punkt3D(float a, float b, float c): Punkt2D(a,b) // konstruktor
{z=c;}
void wypisz2()
{ cout<<x<<" "<<y <<" "<<z;}
// mamy dostęp do danych protected
};
//------------------------------------------------------------------
int main()
{
Punkt2D p2D (1.1, 2.2);
p2D.wypisz1(); cout<<endl;
Punkt3D p3D(5.5,6.6,7.7);
p3D.wypisz2(); cout<<endl;
return 0;}
// tworzymy obiekt klasy Punkt2D
// tworzymy obiekt klasy Punkt3D
15
DZIEDZICZENIE
www.imio.polsl.pl
o
O dostępie do odziedziczonych składników decyduje też
(oczywiście w zakresie ograniczonym do składników public i protected!)
klasa pochodna.
o
Np.: w klasie Lepsza_Pralka jest to słowo public przed nazwą klasy
podstawowej:
class Lepsza_Pralka : public Pralka
{
// ciało klasy pochodnej
};
o
oznacza to, że:
- składniki public z klasy podstawowej będą nadal public;
- składniki protected z klasy podstawowej będą nadal protected .
o
gdyby zamiast public było tam słowo protected lub private to:
tabelka na następnym slajdzie...
16
www.imio.polsl.pl
DZIEDZICZENIE
słowo na liście
dziedziczenia:
składowe
w klasie podstawowej były:
w klasie pochodnej są:
protected
protected
public
public
public
protected
protected
protected
public
protected
private
private
public
o
Klasa pochodna może co najwyżej ograniczyć uprawnienia do odziedziczonych
składników!
o
W ramach naszych rozważań ograniczymy się do wariantu public...
17
DZIEDZICZENIE
www.imio.polsl.pl
Czego się nie dziedziczy:
o
konstruktorów – konstruktor klasy podstawowej nie staje się konstruktorem klasy
pochodnej.
dlaczego?
Klasa pochodna = klasa podstawowa + X
gdzie X: składniki zdefiniowane w klasie pochodnej (których klasa podstawowa nie zna)
zatem – konstruktory klasy pochodnej należy zdefiniować!
o
destruktorów - z tych samych powodów co powyżej.
o
dla zainteresowanych – operatora przypisania =
(jeśli został zdefiniowany w klasie podstawowej).
18
DZIEDZICZENIE
www.imio.polsl.pl
Kolejność uruchamiania konstruktorów:
o
najpierw uruchamiany jest konstruktor klasy podstawowej;
o
w następnej kolejności wykonywane są konstruktory obiektów składowych
klasy pochodnej (jeśli występują składowe obiekty innych klas);
o
dopiero na końcu uruchamiany jest konstruktor klasy pochodnej.
„Klasa uszanuje najpierw starszych, potem swoich gości, a dopiero na samym końcu
zajmie się sobą”.
J. Grębosz: „Symfonia C++ standard”, str. 808 wydania z 2008 roku
19
DZIEDZICZENIE
www.imio.polsl.pl
Konstruktor klasy pochodnej jest zwykłym konstruktorem, przy czym:
o
Na jego liście inicjalizacyjnej można (a często trzeba) umieścić wywołanie konstruktora
klasy podstawowej.
Wywołanie takie można pominąć, gdy:
o
klasa podstawowa nie ma żadnego konstruktora (więc nie ma czego wywołać...);
o
klasa podstawowa ma konstruktory a wśród nich jest konstruktor domyślny.
20
www.imio.polsl.pl
DZIEDZICZENIE
Przykład:
#include <iostream>
using namespace std;
class Prostokat
//
{ protected:
float bok_a, bok_b;
//
public:
Prostokat(float a, float b){bok_a=a; bok_b=b;}
//
void pole()
//
{ cout<<"\nPole prostokata o bokach a="
<<bok_a<<" b="<<bok_b<< " wynosi "<<bok_a*bok_b;}
};
klasa podstawowa
dane protected
konstruktor
funkcja składowa
//------------------------------------------------------------------
class Kwadrat: public Prostokat
// klasa pochodna
{ protected:
float bok;
// dana protected
public:
Kwadrat(float dl):Prostokat(dl, dl)
// konstruktor - wywołanie
{ bok=dl;}
// konstruktora klasy podstawowej
void pole()
// funkcja składowa – nowa wersja!
{ cout<<"\nPole kwadratu o boku a="<<bok<<" wynosi "<<bok*bok;}
};
//------------------------------------------------------------------
int main()
{
Kwadrat k1(2.3);
k1.pole();
k1.Prostokat::pole();
return 0;}
// tworzymy obiekt klasy Kwadrat
// pole kwadratu
// pole prostokąta ("schowanego" w klasie Kwadrat)
21
www.imio.polsl.pl
DZIEDZICZENIE
Przykład bardziej rozbudowany:
class Rolki
{ protected:
string nazwa;
public:
Rolki(string i):nazwa(i) {}
void opis()
{cout<<"\nMam rolki: "<<nazwa<<endl;}
};
// klasa podstawowa
// konstruktor
// f. składowa klasy podstawowej
class Fitness: public Rolki
// pierwsza klasa pochodna
{ private:
int srednica; string zadanie;
// nowe dane składowe
public:
Fitness (string n, int sr, string za= "jade sobie..."):Rolki(n) // konstruktor
{ zadanie=za; srednica=sr;
// przypisania
smigaj(zadanie);}
// wywołanie funkcji składowej
void smigaj(string rob)
// funkcja składowa
{ cout<<"\nTo sa rolki do fitnessu: "<<nazwa<<endl;
cout<<"Kolka "<<srednica<<"mm"<<endl;
cout<<"Cwiczenie: "<<rob<<endl;}
};
22
www.imio.polsl.pl
DZIEDZICZENIE
Przykład bardziej rozbudowany:
class Speed: public Rolki
// druga klasa pochodna
{private:
int srednica;
string lozyska, zadanie;
// nowe dane składowe
public:
Speed (string n, int sr, string lo, string za="rozgrzewka..."):Rolki(n) // k.
{ zadanie=za; srednica=sr; lozyska=lo;
// przypisania
smigaj(zadanie);}
// wywołanie funkcji składowej
void smigaj(string rob)
// funkcja składowa
{ cout<<"\n To sa rolki do jazdy szybkiej: "<<nazwa<<endl;
cout<<" Kolka "<<srednica<<"mm, lozyska: "<<lozyska<<endl;
cout<<" Cwiczenie: "<<rob<<endl;}
};
#include <iostream>
using namespace std;
// to wstawiamy np. na początku pliku...
23
www.imio.polsl.pl
DZIEDZICZENIE
Przykład bardziej rozbudowany:
int main()
{Rolki r1("Znalezione w piwnicy");
r1.opis();
Fitness jakies("Pozyczone do nauki", 76);
// funkcja główna
// obiekt klasy podstawowej
// potem taki obiekt
Fitness rekreacyjne("Rollerblade Spark", 84, "jazda tylem"); // inne obiekty
Speed szybkie("Powerslide infinity", 110, "ABEC 7 Freespin"); // 4 arg. domyślny
rekreacyjne.smigaj("slalom");
szybkie.smigaj("double push");
return 0;}
// fitness: inne ćwiczenie
// szybkie: inne ćwiczenie
24