po w2 id 557612 Nieznany

background image

Programowanie obiektowe

Wykład 2. Dziedziczenie, polimorfizm

background image

Operator zakresu

Operator zakresu ma postać ’::’. Przed nim stawia się nazwę
klasy, przestrzeni nazw bądź nic. Służy do wskazania zakresu, z
którego pochodzi nazwa.

std::cout
Stos::n
::n

background image

zmienna this

czyli wskaźnik do się

this

to specjalna zmienna dostępna w ciele definicji metody

niestatycznej, której wartością jest wskaźnik do obiektu na rzecz
którego metoda została wywołana.

background image

zmienna this

przykłady użycia

class Licznik
{
public:

Licznik() : n(0) {};
Licznik& zwieksz() { ++n; return *this; }

// (1)

Licznik& ustaw(int n) { this->n = n; return *this; }

// (1) (3)

int pokaz() { return n; }

private:

int n;

};

main()
{

Licznik l;
cout << l.ustaw(5).zwieksz().pokaz();

// (2)

}

(1)

metoda zwraca referencję do obiektu na rzecz którego została wywołana

(2)

dzięki temu można dla jednego obiektu wywołać sekwencję metod, jak w
przykładzie (praktyka często stosowana w przypadku metod, które
zmieniają stan obiektu, nie mając przy tym naturalnej wartości)

(3)

zmienna this użyta w celu odwołania się do przysłoniętej nazwy

background image

Składowe statyczne

Składowe statyczne to składowe ”wspólne” dla całej klasy. Są to
składowe związane z klasą, nie konkretnym obiektem.

atrybut statyczny — istnieje tylko jeden egzemplarz takiego
atrybutu dla całej klasy (w przypadku atrybutów
niestatycznych, każdy obiekt ma swój egzemplarz atrybutu)

metoda statyczna — nie jest wywoływana na rzecz
konkretnego obiektu

Na marginesie: W niektórych językach obiektowych (Smalltalk, Ruby) klasa też
jest obiektem, składowe statyczne z C++ odpowiadają tam składowym obiektu
klasy.

background image

Składowe statyczne

definicja i deklaracja atrybutu statycznego

deklaracja

class Stos
{
public:

static const int rozmiar; // to jest tylko deklaracja

private:

static Stos* ostatnio_uzywany_stos;

...
}

definicja:

int Stos::rozmiar=100; // definicję trzeba umieścić poza definicją klasy
Stos* Stos::ostatnio_uzywany_stos = NULL;

w definicji można, a w przypadku składowych stałych — trzeba
zainicjalizować atrybut statyczny

background image

Składowe statyczne

odwołanie do atrybutu statycznego

wewnątrz klasy — zwyczajnie, przez nazwę

cout << rozmiar;
ostatnio_uzywany_stos=this;

// w metodzie niestatycznej

poza zakresem klasy

Stos::rozmiar; // z użyciem operatora zakresu

s.rozmiar;

// tak jak w przypadku składowej niestatycznej

sp->rozmiar;

background image

Składowe statyczne

metody statyczne

Metody statyczne definiuje się tak jak niestatyczne (zwykłe), z tym
że:

definicję/deklarację w ciele klasy poprzedza się słowem static

nie można odwoływać się w nich do składowych niestatycznych

nie można używać zmiennej this

Do metod statycznych odwołyjemy się podobnie jak do atrybutów
statycznych: w ciele definicji metody - przez nazwę, poza klasą z
użyciem operatora zakresu lub wywołując ją ’dla obiektu’, jak
metodę niestatyczną.

background image

Dziedziczenie

Dziedziczenie (ang. inheritance) to technika polegająca na
definiowaniu nowej klasy (klasy pochodnej, podklasy) na
podstawie klasy już istniejącej (klasy bazowej, nadklasy).

składnia:

class A
{

...

}

class B : A

// B jest podklasą klasy A

{

...

}

Klas bazowych może być więcej niż jedna (wtedy oddziela się je
przecinkiem).

background image

Dziedziczenie

klasa pochodna

Klasa pochodna dziedziczy:

wszystkie atrybuty klasy bazowej

metody klasy bazowej, za wyjątkiem

konstruktorów

destruktora

operatora przypisania (będzie omówiony później)

W klasie pochodnej można:

zdefiniować dodatkowe atrybuty

zdefiniować dodatkowe metody

zredefiniować metody zdefiniowane w nadklasie

background image

Dziedziczenie

dostęp do składowych dziedziczonych w klasie pochodnej

Klasa pochodna ma dostęp do składowych publicznych (public) i
chronionych (protected) kasy bazowej. Nie ma dostępu do
składowych prywatnych.

Atrybuty chronione (protected) są dostępne w klasach
pochodnych, poza nimi zachowują się jak prywatne.

background image

Dziedziczenie

zakres widoczności składowych dziedziczonych

Zakres widoczności składowych dziedziczonych w klasie pochodnej
określa się poprzedzając w definicji klasy klasę bazową słowem
public

, protected, lub private (domyślne).

class A : public B
{

// składowe publiczne w B są publiczne w A
// składowe chronione w B są chronione w A

}

class A : protected B
{

// składowe publiczne w B są chronione w A
// składowe chronione w B są chronione w A

}

class A : private B lub class A : B
{

// składowe publiczne w B są prywatne w A
// składowe chronione w B są prywatne w A

}

background image

Dziedziczenie

zakres widoczności składowych dziedziczonych: wybiórcze udostępnianie składowych
dziedziczonych

Możliwe jest też precyzyjniejsze określanie widoczności składowych
dziedziczonych, na poziomie pojedynczych składowych (Symfonia
C++, t. III, pkt. 19.2.4, Po znajomości, czyli udostępnianie
wybiórcze

)

background image

Dziedziczenie

dziedziczenie wielokrotne

Klasa może mieć więcej niż jedną klasę bazową. Dziedziczy wtedy
wszystkie składowe (oprócz konstruktorów, destruktora i op. =) ze
wszystkich klas bazowych.

background image

Dziedziczenie wielokrotne

konflikt nazw

class A
{
public:

int a,i;

}

class B
{
public:

int b,i;

}

class C : public A, public B
{

void f()
{

a = b;

// poprawne

i = 0;

// błąd (niejednoznaczne)

A::i = 0;

// poprawne

}

}

Klasa C dziedziczy obie składowe i, są to różne składowe w klasie C.
Dopiero odwołanie się do składowej i jest błędem (niejednoznaczność).
Niejednoznaczność można usunąć stosując operator zakresu.

background image

Dziedziczenie

a wskaźniki i referencje

Wskaźnik do danej klasy może wskazywać na obiekt klasy
potomnej. Podobnie z referencjami.

background image

Dziedziczenie

wywołanie metod z użyciem wskaźnika i referencji

class A {
public:
void f() { cout << "Metoda z klasy A"; }
};

class B : public A {
public:
void f() { cout << "Metoda z klasy B"; } // metoda zredefiniowana
};

int main() {
A a;
B b;
A *p1 = &a, *p2 = &b;
A &r1 = a, &r2 = b;
a.f();
b.f();
p1->f();
p2->f();
r1.f();
r2.f();
};

background image

Dziedziczenie

wywołanie metod z użyciem wskaźnika i referencji

class A {
public:
void f() { cout << "Metoda z klasy A"; }
};

class B : public A {
public:
void f() { cout << "Metoda z klasy B"; }
};

int main() {
A a;
B b;
A *p1 = &a, *p2 = &b;
A &r1 = a, &r2 = b;
a.f();

// Metoda z klasy A

b.f();

// Metoda z klasy B

p1->f();

// Metoda z klasy A

p2->f();

// Metoda z klasy A

r1.f();

// Metoda z klasy A

r2.f();

// Metoda z klasy A

};

Kiedy znienna typu
wskaźnik do obiektu
klasy A, wskazuje na
obiekt klasy potomnej
B, o wyborze metody
decyduje typ
wskaźnika, nie typ
obiektu (dotyczy
metod
niewirtualnych).

background image

Polimorfizm

Polimorfizm to cecha języka programowania umożliwiająca
operowanie na danych różnego typu za pomocą jednolitego
interfejsu.

background image

Polimorfizm

w języku C?

C nie jest językiem polimorficznym. Polimorficzne zachowanie da
się wyprogramować w dość skomplikowany niskopoziomowy sposób.
Przykład: funkcja qsort

void qsort(void *base, size_t n, size_t size,

int (*cmp) (const void *, const void *) )

background image

Polimorfizm

w języku C++

Polimorfizm w C++ realizowany jest w oparciu hierarchię klas oraz
metody wirtualne. Jest to typowy sposób uzyskiwania polimorfizmu
w językach obiektowych.

W C++ istnieje jeszcze drugi sposób na realizację polimorfizmu: szablony.

background image

Polimorfizm

metody wirtualne

definicję metody wirtualnej poprzedza się słowem virtual

metody wirtualne są normalnie dziedziczone, mogą być w
klasach pochodnych redefiniowane, jak inne, przy czym we
wszystkich klasach pochodnych nadal są metodami
wirtualnymi (redefiniując taką metodę w klasie pochodnej nie
trzeba jej już poprzedzać słowem virtual)

background image

Metody wirtualne

różnica

Wirtualność metody ujawnia się w momencie jej wywołania: jeśli
operujemy wskaźnikiem do obiektu (może on wskazywać na obiekt
dowolnej klasy potomnej) i wywołujemy dla wskazywanego obiektu
metodę wirtualną to o wyborze metody decyduje typ obiektu, nie
wskaźnika. Decyzja co do wyboru metody podejmowana jest
dopiero w trakcie działania programu.

Podobnie z referencjami.

background image

Metody wirtualne

wywołanie metody wirtualnej z użyciem wskaźnika i referencji

class A {
public:
virtual void f() { cout << "Metoda z klasy A"; }
};

class B : public A {
public:
void f() { cout << "Metoda z klasy B"; } // metoda zredefiniowana
};

int main() {
A a;
B b;
A *p1 = &a, *p2 = &b;
A &r1 = a, &r2 = b;
a.f();
b.f();
p1->f();
p2->f();
r1.f();
r2.f();
}

background image

Metody wirtualne

wywołanie metody wirtualnej z użyciem wskaźnika i referencji

class A {
public:
virtual void f() { cout << "Metoda z klasy A"; }
};

class B : public A {
public:
void f() { cout << "Metoda z klasy B"; }
};

int main() {
A a;
B b;
A *p1 = &a, *p2 = &b;
A &r1 = a, &r2 = b;
a.f();

// Metoda z klasy A

b.f();

// Metoda z klasy B

p1->f();

// Metoda z klasy A

p2->f();

// Metoda z klasy B

r1.f();

// Metoda z klasy A

r2.f();

// Metoda z klasy B

}

Kiedy znienna typu
wskaźnik do obiektu
klasy A, wskazuje na
obiekt klasy potomnej
B, o wyborze metody
wirtualnej decyduje
typ obiektu, nie typ
wskaźnika.

background image

Wczesne i późne wiązanie

wczesne wiązanie (early binding)
podczas kompilacji wywołanie metody (funkcji) jest wiązane z
adresem kodu metody

późne wiązanie (late binding)
powiazanie z konkretnym adresem kodu następuje podczas
wykonywania programu: na podstawie dodatkowej informacji
w obiekcie ustalana jest klasa obiektu; sprawdzane jest, czy
wywoływana metoda jest zdefiniowana w tej klasie; jeśli nie,
przeszukiwane są kolejne nadklasy

background image

Wczesne i późne wiązanie

Kompilacja kodu C++

Kompilator C++ stosuje wczesne wiązanie w sytuacjach kiedy
może to zrobić. Również w przypadku metod wirtualnych, jeśli:

są wywoływane na rzecz ’prawdziwego’ obiektu, nie referencji
ani wskaźnika; z poprzedniego przykładu:

A a;
B b;
a.f();
b.f();

operator zakresu rozstrzyga

A a;
B b;
A *p1 = &a, *p2 = &b;
A &r1 = a, &r2 = b;
p1->A::f();
p2->B::f();
r1.A::f();
r2.B::f();

background image

Metody wirtualne

koszty

Metody wirtualne generują koszty.

obiekty klas zawierających choć jedną metodę wirtualną są
większe; obiekt taki zawiera dodatkowo informację pozwalającą
zidentyfikować jego klasę; informacja ta jest wykorzystywana w
trakcie wywołania metody wirtualnej

wywołanie metody wirtualne jest bardziej czasochłonne;
dochodzi czas potrzebny na wybór właściwej wersji metody

background image

Metody abstrakcyjne

Metoda abstrakcyjna to metoda wirtualna, którą wprowadza się bez
podania definicji, określając jedynie sygnaturę (nazwa, argumenty,
typ wartości).
Metodę abstrakcyjną oznacza się, dodając do deklaracji napis ’= 0’

background image

Klasa abstrakcyjna

Klasa zawierająca choćby jedną metodę abstrakcyjną jest klasą
abstrakcyjną. Nie ma możliwości tworzenia obiektów takiej
klasy.

Klasa abstrakcyjna określa jedynie pewien zestaw własności,
które wszystkie klasy potomne będą posiadać.

Klasy abstrakcyjne są narzędziem ułatwiającym modularyzację
kodu.

background image

Klasa abstrakcyjna

przykład

class Figura
{
public:

virtual void narysuj() = 0;

}

Tyle wiedząc, możemy już np. pisać kod wyświetlający figury na
ekranie. Kod ten nie zależy od tego jakie konkretnie figury
wprowadzimy. Dla każdej z figur zdefiniowany będzie sposób jej
rysowania.

class Trojkat

: public Figura

{
public:

void narysuj()

... ;

}

class Prostakat

: public Figura

{
public:

void narysuj()

... ;

}

class Okrag

: public Figura

{
public:

void narysuj()

... ;

}


Wyszukiwarka

Podobne podstrony:
PO lab 5 id 364195 Nieznany
ASK w2 id 70602 Nieznany (2)
Analiza ekon 08 w2 id 60028 Nieznany
PE w2 id 353181 Nieznany
po modernizacji id 364203 Nieznany
po w3 id 557613 Nieznany
PK W2 id 359503 Nieznany
po w1 id 364234 Nieznany
ALF po paracetamolu id 55196 Nieznany
Fizyka W1 W2 id 177235 Nieznany
IiP z w2 2 id 210527 Nieznany
PO W1 2 id 364238 Nieznany
MEN w2 id 293157 Nieznany
PO W3 id 364241 Nieznany
Lunar 100 dzien po dniu id 2739 Nieznany
PC w2 id 351839 Nieznany
mikro w2 id 300746 Nieznany
4OS 2011 w2 id 39382 Nieznany (2)

więcej podobnych podstron