Programowanie obiektowe
Cz. III
17 V 2015
Klasa, składowe, interfejs, ...
F22 ~1.7x106 linii kodu
F35 ~5.7x106 linii kodu
Boeing 787 Dreamliner ~6.5x106 linii kodu
BWM (?) >50x106 linii kodu
17 V 2015 2
Polimorfizm, dziedziczenie
Pojęcia polimorfizmu, dziedziczenia oraz przeciążenia są
związane (głównie) z metodami klasy (funkcjami).
Funkcje składowe i zaprzyjaznione
Funkcje operatorowe
Operatory specjalne
Konwertery typów
Dziedziczenie
Funkcje polimorficzne
17 V 2015 3
Dziedziczenie
Polega na przejmowaniu (dziedziczeniu) właściwości klasy bazowej przez
klasy pochodne. Uzupełnia pola klasy bazowej polami klasy pochodnej z
zachowaniem ich kolejności.
Dziedziczeniu nie podlegają konstruktory ani destruktory.
class BAZOWA{
...
};
class POCHODNA : public BAZOWA {
...
};
17 V 2015 4
Dziedziczenie
Po nazwie klasy pochodnej, po dwukropku podaje się nazwę klasy
bazowej, określając stopień hermetyzacji (ukrycia) komponentów klasy
bazowej w klasie pochodnej.
class wektor_2D{
protected:
double x,y;
};
class wektor_3D : public wektor_2D {
public:
double z;
};
Klasa wektor_3D posiada pola double x,y,z (protected, protected, public)
17 V 2015 5
Dziedziczenie
Jeżeli klasa bazowa jest uprywatniona, to jej publiczne i zabezpieczone
komponenty stają się prywatne w klasie pochodnej. Jeżeli klasa bazowa
jest upubliczniona, to jej publiczne i zabezpieczone komponenty stają się
odpowiednio publiczne i zabezpieczone w klasie pochodnej . W każdym
przypadku komponenty prywatne klasy bazowej nadal pozostają jej
prywatnymi komponentami.
class BAZOWA {
. . .
public:
void pokaz(); //deklaracja funkcji publicznej,
. . .
};
class POCHODNA: private BAZOWA { // prywatna klasa bazowa,
. . .
};
. . .
BAZOWA B; // definicja obiektu B klasy BBZOWA,
POCHODNA P; // definicja obiektu P klasy POCHODNA,
B.pokaz (); // instrukcja dozwolona wszędzie,
P.pokaz (); // instrukcja niedozwolona poza klasą POCHODNA.
17 V 2015 6
Dziedziczenie
Zdefiniowanie w klasie pochodnej komponentu o takiej samej nazwie jak
komponent klasy bazowej oznacza przesłonięcie komponentu klasy
bazowej, a nie jego przeciążenie.
#include
#include
using namespace std;
class wektor_2D{
public:
double x,y;
void pomnoz(double a, double b)
{ x=x*a;
y=y*b; }
};
class wektor_3D : public wektor_2D{
public:
double z;
void pomnoz(double c)
{ z=z*c; }
};
17 V 2015 7
Dziedziczenie
#include
#include
using namespace std;
class wektor_2D{
public:
double x,y;
void pomnoz(double a, double b)
{ x=x*a;
int main()
y=y*b; }
{
};
wektor_2D w1;
wektor_3D w2;
class wektor_3D : public wektor_2D{
public:
w1.x=3;
double z;
w1.y=3;
void pomnoz(double c)
w1.pomnoz(2,2);
{ z=z*c; }
cout << "2D x=" << w1.x << " y="<< w1.y <};
w2.x=4;
w2.y=4;
w2.z=4;
w2.pomnoz(2);
cout << "3D x=" << w2.x << " y="<< w2.y << " z="<< w2.z< w2.wektor_2D::pomnoz(2,2);
cout << "3D x=" << w2.x << " y="<< w2.y << " z="<< w2.z< return 0;
}
17 V 2015 8
Dziedziczenie
#include
#include
using namespace std;
class wektor_2D{
public:
double x,y;
void pomnoz(double a, double b)
{ x=x*a;
int main()
y=y*b; }
{
};
wektor_2D w1;
wektor_3D w2;
class wektor_3D : public wektor_2D{
public:
w1.x=3;
double z;
w1.y=3;
void pomnoz(double c)
w1.pomnoz(2,2);
{ z=z*c; }
cout << "2D x=" << w1.x << " y="<< w1.y <};
w2.x=4;
w2.y=4;
w2.z=4;
w2.pomnoz(2);
cout << "3D x=" << w2.x << " y="<< w2.y << " z="<< w2.z<2D x=6 y=6
w2.wektor_2D::pomnoz(2,2);
3D x=4 y=4 z=8
cout << "3D x=" << w2.x << " y="<< w2.y << " z="<< w2.z<3D x=8 y=8 z=8
return 0;
}
17 V 2015 9
Dziedziczenie
Konstruktory zanim wykona się konstruktor w klasie pochodnej-
wykonywany jest najpierw konstruktor klasy bazowej. Do konstruktora
klasy bazowej można odwołać się tylko na liście inicjacyjnej (w
konstruktorze klasy pochodnej). Jeśli nie ma takiego odwołania to
wywołany będzie bezparametrowy konstruktor klasy bazowej.
//konstruktor klasy bazowej
WEKTOR_2D::WEKTOR_2D(double x=0, double y=0) :x(x),y(Y) {}
//konstruktor klasy pochodnej
WEKTOR_3D::WEKTOR_3D(double z): z(z) {}
// konstruuje on obiekt x=0, y=0, z=z
//ale konstruktor:
WEKTOR_3D::WEKTOR_3D(double x, double y, double z):WEKTOR_2D(x,y),z(z){}
//konstruuje obiekt x=x, y=y, z=z
17 V 2015 10
Dziedziczenie
Konwersję konstruktorową typu z klasy bazowej do klasy pochodnej robi
się przez definicję:
POCHODNA (BAZOWA &);
// np.
WEKTOR_3D::WEKTOR_3D(WEKTOR_2D &a, double z=0):WEKTOR_2D(a), z(z) {}
Domyślny drugi parametr umożliwia wywołanie konstruktora z jednym
parametrem - tworzony jest wówczas obiekt klasy WEKTOR_3D z polem
z=0;
17 V 2015 11
Dziedziczenie
Dziedziczenie sekwencyjne klasy dziedziczą się jedna po drugiej
class A{...};
class B: public A {...};
class C: public B {...};
class D: public C {...};
Klasa D jest "największa" zawiera wszystkie pola klas A,B i C.
Konstruktor klasy D ma postać:
D::D( ..) : C(...) { & }
17 V 2015 12
Dziedziczenie
Dziedziczenie wielobazowe,
konwersje z typów pochodnych do bazowych istnieją tylko wtedy, gdy są
jednoznaczne (tzn. gdy pola klasy bazowej występują jednokrotnie w
klasach pochodnych). Jest to możliwe dzięki dziedziczeniu wirtualnemu
(virtual).
class A{...};
class B{...};
class C: virtual public A, public B {...};
class D: virtual public A, public B {...};
class E: public C, public D {...};
W klasie E zawarto jedną klasę A oraz dwie klasy B.
Musi ona (klasa A) być dziedziczona wirtualnie w klasach C i D by była
wirtualną w klasie E.
17 V 2015 13
Funkcje polimorficzne
Funkcje polimorficzne (wirtualne) są funkcjami zadeklarowanymi ze
specyfikatorem virtual oraz są wszystkimi funkcjami tego samego typu
zawartymi w dowolnej klasie pochodnej w ciągu dziedziczonych klas.
Wywołanie funkcji polimorficznej na rzecz wskazanego obiektu dokonuje
się z klasy tego obiektu, nie zaś z klasy wskaznika, który go wskazuje.
W konstruktorach i destruktorach funkcje polimorficzne zachowują się tak
jak funkcje zwykłe.
class BAZOWA{
public:
met_A(...);
virtual met_B(...);
};
class POCHODNA: public BAZOWA{
public:
met_A(...);
met_B(...);
};
17 V 2015 14
Funkcje polimorficzne
class BAZOWA{
public:
met_A(...);
virtual met_B(...);
};
class POCHODNA: public BAZOWA{
public:
met_A(...);
met_B(...);
};
POCHODNA X;
BAZOWA *WSK=&X;
WSK->met_A(...); //wywołana będzie funkcja met_A z klasy BAZOWA na rzecz podobiektu
klasy BAZOWA zawartego w obiekcie X, bo WSK jest wskaznikiem do typu BAZOWA
WSK->met_B(...); //wywołana zostanie wirtualna funkcja met_B z klasy POCHODNA na
rzecz obiektu X bo wskaznik WSK wskazuje na obiekt X klasy POCHODNA.
17 V 2015 15
Funkcje polimorficzne
class WEKTOR_2D {
public:
double suma();
virtual double modul();
};
class WEKTOR_3D: public WEKTOR_2D {
public:
double suma();
double modul();
};
double WEKTOR_2D::suma() {return x+y;}
double WEKTOR_2D::modul() {return sqrt(x*x+y*y);)
double WEKTOR_3D::suma() {return x+y+z;}
double WEKTOR_3D::modul() {return sqrt(x*x+y*y+z*z);}
WEKTOR_3D V(-1,-1,0);
WEKTOR_2D *wsk=&V;
wsk->suma() // suma z klasy WEKTOR_2D (wsk jest typu WEKTOR_2D*).
wsk->modul() // z klasy WEKTOR_3D (wsk wskazuje na V- czyli na obiekt tejże klasy
17 V 2015 16
Funkcje polimorficzne
#include
using namespace std;
int main()
class wektor_2D{
public:
{
double x,y;
double wynik=0;
virtual double pomnoz();
wektor_4D w1;
};
wektor_3D w2;
class wektor_3D : public wektor_2D{
w1.x=2; w1.y=3; w1.z=4; w1.u=5;
public:
w2.x=2; w2.y=3; w2.z=4;
double z;
double pomnoz();
};
wektor_2D *wsk=&w2;
class wektor_4D : public wektor_3D{
wynik= wsk->pomnoz();
public:
cout << " Wynik="< double u;
double pomnoz();
};
wsk=&w1;
wynik=wsk->pomnoz();
double wektor_2D::pomnoz()
{ return x*y; } cout << " Wynik="<double wektor_3D::pomnoz()
return 0;
{ return x*y*z;}
}
double wektor_4D::pomnoz()
{ return x*y*z*u;}
17 V 2015 17
Funkcje polimorficzne
#include
using namespace std;
int main()
class wektor_2D{
public:
{
double x,y;
double wynik=0;
virtual double pomnoz();
wektor_4D w1;
};
wektor_3D w2;
class wektor_3D : public wektor_2D{
w1.x=2; w1.y=3; w1.z=4; w1.u=5;
public:
w2.x=2; w2.y=3; w2.z=4;
double z;
double pomnoz();
};
wektor_2D *wsk=&w2;
class wektor_4D : public wektor_3D{
wynik= wsk->pomnoz();
public:
cout << " Wynik="< double u;
double pomnoz();
};
wsk=&w1;
wynik=wsk->pomnoz();
double wektor_2D::pomnoz()
{ return x*y; } cout << " Wynik="<double wektor_3D::pomnoz()
return 0;
{ return x*y*z;}
}
Wynik = 24
double wektor_4D::pomnoz()
Wynik = 120
{ return x*y*z*u;}
17 V 2015 18
Funkcje czysto wirtualne
Funkcje czysto wirtualne i klasy abstrakcyjne,
Taka metoda nigdy nie powinna się wykonać a klasa staje się klasą
wirtualną. Jest to
#include
class Figura{
public:
virtual float pole() = 0;
int main() {
};
Kwadrat A( 2);
Kolo B( 2 );
class Kwadrat : public Figura {
std::cout << A.pole() << std::endl;
public:
std::cout << B.pole() << std::endl;
Kwadrat( const float bok ) : a( bok ) {}
float pole() { return a * a; }
return 0;
private:
}
float a; // bok kwadratu
};
4
12.56
class Kolo : public Figura {
public:
Kolo( const float promien ) : r( promien ) {}
float pole() {return 3.14159 * r * r;}
private:
float r; // promien kola
};
17 V 2015 19
Wykorzystanie obiektów
Pojęcia klasy, składowych oraz interfejsu w obiektowym
paradygmacie programowania
Cykl życia obiektów, konstruktory i destruktory
Polimorfizm kodu poprzez użycie mechanizmów
przeciążania i dziedziczenia
Podsumowanie wykładów
17 V 2015 20
Programowanie obiektowe vs strukturalne
Przykład- program typu Baza Danych:
Struktura
Funkcja
Obiekt
Realizacja
W obiekcie & ?
17 V 2015 21
Programowanie obiektowe vs strukturalne
Obiektowo :
class Ludzie{
Klasa
public:
string imie;
string nazwisko;
string adres;
int wiek;
void dodaj_osobe(string i, string n, string a, int w)
{
imie=i;
nazwisko=n;
adres=a;
wiek=w;
}
};
struct Osoba {
string imie;
string nazwisko;
string adres;
int wiek;
struktura
};
17 V 2015 22
Obiekt programowanie obiektowe
Baza danych
(1000 obiektów)
Samochód 1
Cechy
Osiągi
Zewnętrzne Wewnętrzne
Marka Kolor Cena Silnik Pojemność Moc Vmax Spalanie
Miasto Trasa
Liczba Liczba Liczba
Double Double Double
Normal Metalic
Lista marek
String [ ]
Liczba Liczba
Lista
Double Double
String [0]= Diesel
Liczba
Lista kolorów
String [0]= Benzynowy
Double
String [ ]
17 V 2015 23
Struktura programu w C++
#include
Preprocesor
#include
zadania wykonywane przed kompilacją
...
obszar na deklaracje i definicje
...
&
int main()
{
Funkcja Main
cout<< sqrt(2)<< endl;
return 0;
}
17 V 2015
Funkcje - parametry
bool aktualizacja(int &x, int &y)
{
bool wynik=false;
if (x>y) {
y=x;
wynik=true;
}
else if (y>x) {
x=y;
wynik=true;
}
else if (y==x){
wynik=false;
}
return wynik;
}
int main()
{
int a=2,b=3;
if (!aktualizacja(a,b)){
cout << "a=b";
}
}
17 V 2015
C++ obiektowo
Zmienne referencyjne
zespolona& zespolona::operator+(zespolona &z)
{
zespolona *x= new zespolona;
x->Re=Re+z.Re;
x->Im=Im+z.Im;
return *x;
}
ostream &operator<<(ostream &wyj, zespolona &z)
{
return wyj << '(' << z.Re << ',' << z.Im << ')';
}
Wynikiem jest argument wyj (referencyjny wynik globalnego operatora wyjścia
<<).
Aby można było przekazać w wyniku referencję do arg. formalnego musi on
(arg. formalny) być też typu referencyjnego. Inaczej zostanie argumentem
lokalnym niszczonym poza ciałem funkcji.
17 V 2015 26
Klasa
Klasa jest odmianą struktury
Definicja klasy tworzy nowy typ
sekcja prywatna:
class worek {
komponenty w tej sekcji są dostępne tylko w funkcjach swojej klasy oraz w funkcjach
private:
zaprzyjaznionych z tą klasą (atrybut friend)
&
protected:sekcja zabezpieczona:
komponenty zabezpieczone mogą być dostępne w klasach pochodnych (prywatne nie
&
mogą)
public:
&
sekcja publiczna:
};
Komponenty w sekcji publicznej są dostępne wszędzie.
17 V 2015 27
Konstruktory
Konstruktor jest to funkcja o nazwie klasy, bez typu (bez void) nie zwracająca
wartości.
Jeśli nie został zdefiniowany żaden konstruktor, to niejawnie jest definiowany konstruktor
bezparametrowy Klasa() i konstruktor kopiujący Klasa(Klasa&).
Jest on niejawnie wykonywany przy tworzeniu obiektu. Jego zadanie to zorganizowanie
tworzonego obiektu. Domyślny konstruktor rezerwuje tylko pamięć. Czasem zachodzi
potrzeba inicjalizacji zmiennych obiektu czy alokacji pamięci.
class ZESP{
private:
double Re, Im;
public:
ZESP (double re, double im)
{ Re=re; Im=im;}
}
Tworząc obiekt typu ZESP można dzięki konstruktorowi nadać wartości początkowo polu
Re oraz Im;
17 V 2015 28
Konstruktory
Destruktor
jest to bezargumentowa funkcja o tej samej nazwie co KLASA ze znakiem~.
~KLASA()
Jest wywoływany niejawnie gdy usuwany jest obiekt danej klasy.
Wywołanie destruktora na rzecz obiektu nie usuwa go a jedynie wywołuje funkcję
destruktora.
Jeśli w obiekcie są zaalokowane bufory to domyślny destruktor ich nie usuwa i będą one
ciągle w pamięci. Bufory takie muszą być usuwane przez odpowiednio zdefiniowany
destruktor.
tekst::~tekst()
{
if (txt) delete txt;
txt=NULL;
}
Destruktor wykonywany jest przed usunięciem obiektu.
17 V 2015 29
Konstruktory
class tekst {
private:
int len,tmp;
char *txt;
public:
konstruktor bezpar.
tekst();
tekst(tekst &);
konstruktor kopiujący
tekst(char *);
konstruktor konwersji z typu char *
~tekst();
destruktor
tekst &operator=(const tekst&);
const tekst &operator+(const tekst&);
tekst &operator+=(tekst &);
friend const tekst &operator+(char *, tekst &);
friend ostream &oerator<<(ostream&,const tekst&);
};
tekst::tekst(): len(0),temp(0),txt(NULL){}
tekst::tekst(tekst &s):len(s.len),tmp(0){
if (s.txt){
txt=new char [len+1];
if (txt) strcpy(txt,s.txt);
else len=0;
}
else txt=NULL;
if (s.tmp) delete &s;
}
17 V 2015 30
Polimorfizm, dziedziczenie, przeciążenie ...
Funkcje operatorowe:
Obiekty są "normalnymi" zmiennymi o określonym typie, więc można na
nich wykonywać działania np. matematyczne.
int x,y;
x=10;
y=20;
x=y+10;
Samochody A,B,C;
C=A+B;
Z tą różnicą- że należy zdefiniować operatory, by sprecyzować w jaki
sposób mają one (operatory) wpływać na obiekty (np. A i B).
17 V 2015 31
Polimorfizm, dziedziczenie, przeciążenie ...
Funkcje operatorowe:
Jeśli funkcja operatora jest tylko zaprzyjazniona z daną klasą to jej
pierwszy argument jest lewym argumentem operatora.
class Wekt{
int x,y;
public:
Wekt(int x=0, int y=0)
{ this->x=x;this->y=y;}
Wekt operator+(Wekt a)
{return Wekt(this->x+a.x, this->y+a.y);}
friend ostream &operator<<(ostream &c, Wekt &d)
{return c<< "("<< d.x << "," << d.y <<")";}
};
int main()
w3=w1.operator +(w2);
{
Wekt w1(1,2),w2(3,4),w3,w4;
cout << w1 << "+" << w2 << endl;
w3=w1+w2;
cout << w3 << endl;
}
17 V 2015 32
Dziedziczenie
Po nazwie klasy pochodnej, po dwukropku podaje się nazwę klasy
bazowej, określając stopień hermetyzacji (ukrycia) komponentów klasy
bazowej w klasie pochodnej.
class wektor_2D{
protected:
double x,y;
};
class wektor_3D : public wektor_2D {
public:
double z;
};
Klasa wektor_3D posiada pola double x,y,z (protected, protected, public)
17 V 2015 33
Dziedziczenie
Zdefiniowanie w klasie pochodnej komponentu o takiej samej nazwie jak
komponent klasy bazowej oznacza przesłonięcie komponentu klasy
bazowej, a nie jego przeciążenie.
#include
#include
using namespace std;
class wektor_2D{
public:
double x,y;
void pomnoz(double a, double b)
{ x=x*a;
y=y*b; }
};
class wektor_3D : public wektor_2D{
public:
double z;
void pomnoz(double c)
{ z=z*c; }
};
17 V 2015 34
Dziedziczenie
#include
#include
using namespace std;
class wektor_2D{
public:
double x,y;
void pomnoz(double a, double b)
{ x=x*a;
int main()
y=y*b; }
{
};
wektor_2D w1;
wektor_3D w2;
class wektor_3D : public wektor_2D{
public:
w1.x=3;
double z;
w1.y=3;
void pomnoz(double c)
w1.pomnoz(2,2);
{ z=z*c; }
cout << "2D x=" << w1.x << " y="<< w1.y <};
w2.x=4;
w2.y=4;
w2.z=4;
w2.pomnoz(2);
cout << "3D x=" << w2.x << " y="<< w2.y << " z="<< w2.z<2D x-6 y=6
w2.wektor_2D::pomnoz(2,2);
3D x=4 y=4 z=8
cout << "3D x=" << w2.x << " y="<< w2.y << " z="<< w2.z<3D x=8 y=8 z=8
return 0;
}
17 V 2015 35
Funkcje polimorficzne
Funkcje polimorficzne (wirtualne) są funkcjami zadeklarowanymi ze
specyfikatorem virtual oraz są wszystkimi funkcjami tego samego typu
zawartymi w dowolnej klasie pochodnej w ciągu dziedziczonych klas.
Wywołanie funkcji polimorficznej na rzecz wskazanego obiektu dokonuje
się z klasy tego obiektu, nie zaś z klasy wskaznika, który go wskazuje.
W konstruktorach i destruktorach funkcje polimorficzne zachowują się tak
jak funkcje zwykłe.
class BAZOWA{
public:
met_A(...);
virtual met_B(...);
};
class POCHODNA: public BAZOWA{
public:
met_A(...);
met_B(...);
};
17 V 2015 36
Koniec
17 V 2015
Wyszukiwarka
Podobne podstrony:
Wyklad progr obiekt cz II
Wyklad progr obiekt cz I a
Podstawy edytorstwa wykład cz III
LIMS system zarządzania działalnością laboratorium Cz III Uprawnienia i rozwiązania indywidualne
Wyklad 7 Inwestycje materialne cz 1
Algorytmy i złożoność cz III
Problemy bohaterów Dziadów cz III i Wesela wobec proble~963
Arch wykład nr 5 Ściskanie cz 1
o Wstęp do cz III Czy myślimy matematycznie
Prawo rzymskie cz III prawo osobowe z czynnościami prawnymi
kurs od marzenia do sukcesu cz iii
Jezyki i paradygmaty cz III
BO IIIsem MNied cz III
więcej podobnych podstron