inf2 w07 id 213009 Nieznany

background image

Wykład 7

C++:

Przeciążanie operatorów, Wzorce

projektowe, Zmienne dynamiczne

Wskaźniki i referencje,

Operator przypisania

Relacje, Dziedziczenie, Polimorfizm

background image

itm / MVLab (c) 2007-2011

Przeciążanie operatorów

Powód:

l

Dla standardowych typów w C istnieje szereg zdefiniowanych
operatorów

l

Dla nowo tworzonych typów (klas) powinna być także

możliwość zdefiniowania analogicznych, intuicyjnych
operatorów

#include "Ulamek.h"
void main()
{

CUlamek ulamekA(1,2),

ulamekB = 3,
ulamekC;

ulamekC = ulamekA + ulamekB;
ulamekC *= ulamekA;
int c;

if(c<=0.2)
{ //...

};

TestUlamek.cpp(22):

error C2676:

Operator binarny '+':

'CUlamek' nie definiuje

takiego operatora lub konwersji

do operatora predefiniowanego.

background image

itm / MVLab (c) 2007-2011

Zły przykład: operatory

#include "Ulamek.h"
// ...
CUlamek Add (CUlamek U2) {
m_iLicznik =

m_iLicznik * U2.m_iLicznik +
m_iMianownik *
U2.m_iLicznik;

m_iMianownik = U2.m_iMianownik;
return *this;
};
CUlamek Mul (CUlamek U2) {
m_iLicznik *= U2.m_iLicznik;
m_iMianownik *= U2.m_iMianownik;
return *this;
};

class CUlamek
{
private:

int m_iLicznik;
int m_iMianownik;

public:

CUlamek(

const CUlamek& kUlamek

);

CUlamek(int iLicznik);
CUlamek(int iLicznik,

int iMianownik);

CUlamek Add (CUlamek U2);
CUlamek Sub (CUlamek U2);
CUlamek Mul (CUlamek U2);
CUlamek Div (CUlamek U2);

};

#include "Ulamek.h"
void main()
{

CUlamek ulamekA(1,2), ulamekB(3), ulamekC;
ulamekC = (ulamekA.Add(ulamekB)).Mul(ulamekC);
// ...

};

Nigdy

w ten

sposób

background image

itm / MVLab (c) 2007-2011

Przeciążanie operatorów –

Przykład '~'

#include "Ulamek.h"
// ...
CUlamek operator~() const {

if(!m_iMianownik) exit(1);
CUlamek tmp(m_iMianownik, m_iLicznik);
return tmp;

};
CUlamek operator*(const CUlamek&

aU) const {

CUlamek tmp(

m_iLicznik*aU.m_iLicznik,
m_iMianownik*aU.m_iMianownik);

return tmp;

};

class CUlamek
{

private:

int m_iLicznik;
int m_iMianownik;

public:

// ...
CUlamek operator~() const;
CUlamek operator*(

const CUlamek& aU)

const;

CUlamek operator=(const Culamek& aU);
// ...

};

#include "Ulamek.h"
void main()
{

CUlamek ulamekA(1,2), ulamekB(3);
Culamek ulamekC = ~ulamekA;

(ulamekA * ulamekB).Wypisz();

};

background image

itm / MVLab (c) 2007-2011

Przeciążanie operatorów

Przykład

#include "Ulamek.h"
// ...
CUlamek operator~() const {

if(!m_iMianownik) exit(1);
CUlamek tmp (m_iLicznik,

m_iMianownik);

return tmp;

};
CUlamek operator*(const CUlamek&

aU) const {

CUlamek tmp(

m_iLicznik*aU.m_iLicznik,
m_iMianownik*

aU.m_iMianownik);

return tmp;

};

Zwracanie wartości

bez użycia referencji:
po przetworzeniu obiektu

przez metodę,

lokalny obiekt jest niedostępny.
Kompilator zwykle nie dostrzega
tego problemu.

background image

itm / MVLab (c) 2007-2011

Przeciążanie operatorów

Przykład '='

#include "Ulamek.h"
// ...
CUlamek& operator=(const CUlamek& aU)
{ //sprawdzenei konieczne w przypadku

//komponentów dynamicznych
//np. ulamekA = ulamekA
if(this == &aU)

return *this;

m_iLicznik = aU.m_iLicznik;
m_iMianownik = aU.m_iMianownik;
return *this;

class CUlamek
{
private:

int m_iLicznik;
int m_iMianownik;

public:

// ...
CUlamek operator~() const;
CUlamek operator*(

const CUlamek& aU)

const;

CUlamek operator=(const CUlamek& aU);
// ...

};

#include "Ulamek.h"
void main()
{

CUlamek ulamekA(1,2), ulamekB(3), ulamekC;
ulamekC = ulamekA * (~ulamekB);
ulamekC.Wypisz();

};

Obiekt którego

metoda została wywołana

(a nie jego kopia!!)

background image

itm / MVLab (c) 2007-2011

Wzorce klas

l

Używanie funkcji jest zależne od typów danych jakie one

obsługują. Powoduje to m.in. konieczność ich przeciążania.

l

Zasadniczo ta sama funkcjonalność musi być często udostępniana

dla różnych typów danych. Przeciążanie funkcji celem umożliwienia

współpracy z różnymi typami powoduje:

l

większy nakład programistyczny,

l

trudności w analizie kodu,

l

większe prawdopodobieństwo błędów,

l

problemy z ich znalezieniem w gąszczu podobnych funkcji.

l

Przykładem jest bufor FIFO który działa tak samo dla wszystkich

możliwych typów danych,

l

Rozwiązaniem jest parametryzacja funkcji i klas pod względem
typów w postaci tzw. wzorców (szablonów -ang. templates).

→ programowanie generyczne

l

wzorce klas

l

wzorce funkcji

background image

itm / MVLab (c) 2007-2011

Implementacja wzorców

przykład

// Wzorzec funkcji zwracającej większą wartość z dwóch podanych
template<class T> T Max (T wart1, T wart2) {

if(wart1>wart2) return wart1;
else return wart2; }

// ...
CUlamek ulamekA(2,3), ulamekB(3,4), ulamekC;
ulamekC = Max(ulamekA,ulamekB);
int i = Max(4,5);

// Wzorzec klasy CLista
template<class T> class CLista {
public:

Clista();
~Clista();
void dolacz(T);
T podajOstatni(T);
void usunOstatni();
//...

};
Clista<CUlamek> mojaLista;
CUlamek ulamekA(2,3);
mojaLista.dolacz(ulamekA);

Typ T zostanie określony dalej,

podczas wywoływania funkcji;

można podać np. int -wówczas

zarówno argumenty, jak

i typ zwracany też zostaną

zamienione na int

Tu również na tej samej

zasadzie zadziała typ

parametryczny T.

mojaLista (typu CLista<CUlamek>)

będzie działała dla typu Clista

-

wszędzie tam,

gdzie w definicji wpisany był typ T.

background image

itm / MVLab (c) 2007-2011

Zasady postępowania z wzorcami

l

Wzorce nie mogą być (pre-)kompilowane oddzielnie.

W tym celu muszą istnieć odpowiednie zależności,
parametryzowane przez sam wzorzec -

zwykle nie powoduje to błędów.

l

Wzorce muszą być zadeklarowane i zdefiniowane w jednym pliku.

Są one łączone wg zapotrzebowań.
Kompilator generuje sprecyzowane wersje klas opartych na wzorcach

dopiero w przypadku odpowiedniego wywołania.

Ulamek

.h

Ulamek

.cpp

TestUlame

k

.cpp

Kompil

ator

Kompil

ator

Ulamek

.obj

TestUlamek

.obj

Linker

TestUlamek

.exe

Wzorzec

.t

Wzorzec

.t

background image

itm / MVLab (c) 2007-2011

Pamięć dynamiczna

l

Zmienne i tablice są statyczne i nieelastyczne
-

nie można zmieniać ich rozmiaru.

l

Co zrobić gdy ilość dostępnej pamięci
jest w czasie programowania nieznana? np.:

l

przetwarzanie tekstu -ile liter?

l

obsługa MP3 -ile piosenek?

l

Rozwiązaniem jest zastosowanie pamięci dynamicznej

o modyfikowalnym rozmiarze. Jeśli trzeba alokuje się dodatkową

przestrzeń w pamięci, jeśli nie -można ją zwolnić dla innych potrzeb.

l

Cele:

l

efektywne gospodarowanie pamięcią,

l

elastyczność,

l

dopasowanie do zasobów systemowych.

background image

itm / MVLab (c) 2007-2011

Pamięć dynamiczna w C++

Dlaczego nie tak jak w C?

l

Wady malloc() i free()

l

wysokie wymagania od programisty

l

niebezpieczeństwo naruszenia zasad ochrony

pamięci

l

brak dopasowania do filozofii obiektowej

l

Rozwiązanie: operatory new() i delete()

l

dynamiczna obsługa pamięci w C++ za pomocą operatorów new i delete

l

zastosowanie zarówno do typów standardowych jak i do klas

l

automatyczne (niejawne) wywołania konstruktora w przypadku klas

l

operatory new i delete można także przeładowywać w obrębie klasy

l

new i delete istnieją zawsze razem
-

każdy dynamicznie powołany obiekt musi być w C++ niejawnie usunięty.

background image

itm / MVLab (c) 2007-2011

new i delete -

przykłady

int* piMojaLiczba = new int;
*piMojaLiczba = 4711;
delete piMojaLiczba;

int iRozmiar = 5;
int* piPole = new int [iRozmiar];
for(int j=0; j<iRozmiar; j++)

piPole[j]=j*11;

delete[] piPole;

CUlamek *pUlamekA = new CUlamek;
CUlamek *pUlamekB = new CUlamek;
CUlamek *pUlamekC = new CUlamek;
pUlamekC = pUlamekB;
//...
delete pUlamekA;
delete pUlamekB;
delete pUlamekC;

4711

piMojaLiczba

44

piPole

33

22

11

0

26

1

L

M

5
8

L

M

0
1

L

M

pUlamekC

pUlamekB

pUlamekA

wywołanie konstruktorów

pUlamekC

„wisi w powietrzu”

„wysypanie” programu

dynamiczna alokacja tablicy

dynamiczna dealokacja tablicy

(delete bez nawiasów klamrowych

spowoduje usunięcie wyłącznie

pierwszego elementu)

brak konieczności

konwersji typów

(typ jest ten sam)

background image

itm / MVLab (c) 2007-2011

Przykład:

konstruktor konwertujący

// MyString.h
class CMyString
{
public:

CMyString();
CMyString(const char*);
~CMyString();
void pokaz();

private:

int m_iDlugosc;
char* m_pszBuf;

};

#include "MyString.h"
#include <cstring>
#include <iostream>
using namespace std;
CmyString::CMyString() {

m_iDlugosc = 0;
m_pszBuf = NULL;

};
CMyString::CMyString(const char* pszName {

m_iDlugosc = strlen(pszName);
m_pszBuf = new char[m_iDlugosc+1];
strcpy(m_pszBuf, pszName);

};
CmyString::~CMyString() {

delete[] m_pszBuf;

};
void CmyString::pokaz() {

cout << "STRING-Objekt: " << m_pszBuf;

};

#include "MyString.h"
void main() { CMyString mojString("To jest String");}

m_iDlugosc

m_pszBuf

14

T o

j e s t

S t r i n g

\0

mojString

konstruktor

korzysta z pamięci

podręcznej

dealokacja

w obrębie destruktora

automatyczne

wywołanie

destruktora

na końcu bloku

background image

itm / MVLab (c) 2007-2011

Przykład:

konstruktor konwertujący

#include "MyString.h"
#include <cstring>
#include <iostream>
using namespace std;
CmyString::CMyString() {

m_iDlugosc = 0;
m_pszBuf = NULL;

};
CMyString::CMyString(const char* pszName {

m_iDlugosc = strlen(pszName);
m_pszBuf = new char[m_iDlugosc+1];
strcpy(m_pszBuf, pszName);

};
CmyString::~CMyString() {

delete[] m_pszBuf;

};
void CmyString::pokaz() {

cout << "STRING-Objekt: " << m_pszBuf;

};

#include "MyString.h"
void main() { CMyString mojString("To jest String");}

UWAGA!

W przypadku

pamięci dynamicznej

ostrożności nigdy za wiele

if(m_pszBuf!=NULL)

delete[] m_pszBuf;

m_pszBuf = NULL;

background image

itm / MVLab (c) 2007-2011

Dynamiczne
komponenty i kopie

Płaskie kopie

l

Standardowo kopiowanie ani przypisanie nie powiela

zawartości dynamicznej, przez co dynamiczna zawartość

staje się przynależna do wielu obiektów

l

Ważne w przypadku konstruktorów kopiujących
oraz operatorów przypisania.

CMyString String1("Pierwszy String");

//Niejawne wyw. konstr. kopującego:
CMyString String2 = String1;
CMyString String3;
//Niejawne wyw. operat. przypisania:
String3 = String1;
//String4 pozostawiony "w powietrzu":
CMyString String4("Czwarty String");
String4 = String1;

15

P i e r w s z y

S t r i n g

\
0

15

15

15

String4

String3

String2

String1

C z w a r t y

S t r i n g

\
0

Zamiany dokonane

w którymkolwiek stringu

mają wpływ na inne!

„Wisi

w powietrzu!”

background image

itm / MVLab (c) 2007-2011

Dynamiczne
komponenty i kopie

Głębokie kopie

l

Dla każdej operacji kopiowania

zostaje zaalokowana pamięć do której kopiowana jest ta sama zawartość,

jednak w innym, indywidualnie przydzielonym miejscu w pamięci.

CMyString String1("Pierwszy String");

//Niejawne wyw. konstr. kopującego:
CMyString String2 = String1;
CMyString String3;
//Niejawne wyw. operat. przypisania:
String3 = String1;

//Przygotowanie pamięci dla String4
CMyString String4("Czwarty String");
String4 = String1;

15

P i e r w s z y

S t r i n g \0

15

15

15

String4

String3

String2

String1

C z w a r t y

S t r i n g

\0

Usunięty

P i e r w s z y

S t r i n g \0

P i e r w s z y

S t r i n g \0

P i e r w s z y

S t r i n g \0

background image

itm / MVLab (c) 2007-2011

Przykład: głębokie kopiowanie

własny konstruktor kopiujący i przeciążenie operat.

// MyString.h
class CMyString
{
public:
//...

CmyString(const

CMyString&);

CMyString& operator=

(const CMyString&);

private:

int m_iDlugosc;
char* m_pszBuf;

};

CMyString::CMyString(const CMyString&

argString)

{

m_iDlugosc = argString.m_iDlugosc;
if(m_iDlugosc == 0) m_pszBuf = NULL;
else {

m_pszBuf = new char[m_iDlugosc+1];
strcpy(m_pszBuf, argString.m_pszBuf);

}

}
CMyString& CMyString::operator= (const

CMyString& argString)

{ if(this == &argString) return *this;

m_iDlugosc = argString.m_iDlugosc;
if(m_pszBuf != NULL) delete[] m_pszBuf;
if(m_iLaenge == 0) m_pszBuf = NULL;
else {

m_pszBuf = new char[m_iDlugosc+1];
strcpy(m_pszBuf, einString.m_pszBuf);

}
return *this;

}

zabezpieczenie

przed

samozniszczeniem

background image

itm / MVLab (c) 2007-2011

Podsumowanie rozdz. 4.3

•Konstruktory

(standardowe, kopiujące,

konwertujące, inne)

•Destruktory

•Inicjalizacja podczas
• tworzenia instancji
•usuwanie obiektów

•dopasowywanie funkcji

obsługa innych obiektów

•operatory

pozostałe funkcje

Metody

obsługa pamięci

statyczna/dynamiczna

jawne i niejawne

wywołania

przeciążanie

wzorce

przestrzenie

nazw

płytkie

i głębokie

kopiowanie,

głęboki

operator

przypisania

zwracanie wartości

przez referencję

typ metody

(czy zmienia stan?)

background image

itm / MVLab (c) 2007-2011

Rozróżnianie wskaźników
i referencji

CUlamek* p_ulamek = &ulamek1;

if(p_ulamek!=NULL) //p_iPole!=NULL;

delete p_ulamek; //delete[] p_iPole;

p_ulamek=NULL; //p_iPole=NULL;

5

12

L

M

11

45

L

M

p_ulamek

Ulamek1
0x0011fec1

Ulamek2
0x0011fec9

CUlamek* p_ulamek = new CUlamek;
int *p_iPole = new int[40];

zwykle użycie w C

zwykłe użycie w C++

dowolna pozycja

znaku wskaźnika

Dynamiczna obsługa pamięci za

pomocą new i delete

zabezpieczenie przed użyciem

operatora delete

na rzecz wskaźnika do NULL

Wskaźnik

zmienna która zawiera adres obszaru pamięci

można wskazywać na: zmienne, obiekty, obszary kodu

możliwa wartość NULL oraz wkaźniki do niesprecyzowanego

typu

arytmetyka wskaźników (np. dostęp do zmiennych)

background image

itm / MVLab (c) 2007-2011

Rozróżnienie wskaźników
i referencji

Referencje (nowy element składni C++)

l

Referencje dostarczają odnośników do obiektów

l

Analogicznie do wskaźników: odnośnik do adresu w pamięci

l

W C++

każdy obiekt automatycznie dostaje swoją referencję

CUlamek ulamek1(1,2);
//pobranie referencji
CUlamek& aliasulamka = ulamek1;

operator+(const CUlamek& n_ulamek){

this->m_iz=m_iz+n_ulamek.m_iz;

};

0
1

L

M

l

Zastosowanie referencji jest, w porównaniu do wskaźników, pewniejsze,

ponieważ wskazują zawsze jeden, dokładnie zdefiniowany obiekt,

l

Brak arytmetyki –

referencje nie mogą być np. inkrementowane

l

Mechanizm przekazywania parametrów call-by-reference

l

Dostępne jak „normalne” zmienne

ALE: pomimo takiej samej pisowni

operator referencji jest łatwo odróżnialny
od operatora adresu

Op. referencji jest używany zwykle
w deklaracjach –zaraz za typem danych

Op. adresu używa się przy operacjach
na zmiennych i stoi zwykle przed ich nazwami

background image

itm / MVLab (c) 2007-2011

Dokładniej o operatorze
przypisania I

l

Sumowanie atrybutów dwóch obiektów CUlamek;

l

Wynik typu CUlamek;

l

Niejawne wywołanie konstruktora kopiującego;

Dlaczego nie można zastosować zwracania wartości przez referencję?

l

Lokalne kopie obiektów zostaną na końcu działania funkcji usunięte

l

Wobec tego także referencja…

CUlamek ulamek1(4,6);
CUlamek ulamek2(5);
//pobranie referencji
CUlamek suma = ulamek1 + ulamek2;
suma.wyswietl();

CUlamek CUlamek::operator+ (const CUlamek &n_ulamek) {

CUlamek tmp(

(this->m_iLicznik+n_ulamek.m_iLicznik),
(this->m_iMianownik+n_ulamek.m_iMianownik));

return tmp; }

9

7

L

M

4

6

L

M

5

1

L

M

=

+

suma

ulamek1

ulamek2

W przypadku operatorów

wartość lewa i prawa

muszą

być identyczne

background image

itm / MVLab (c) 2007-2011

Dokładniej o operatorze
przypisania I

l

Sumowanie atrybutów dwóch obiektów CUlamek;

l

Wynik typu CUlamek;

l

Niejawne wywołanie konstruktora kopiującego;

Dlaczego nie można zastosować zwracania wartości przez referencję?

l

Lokalne kopie obiektów zostaną na końcu działania funkcji usunięte

l

Wobec tego także referencja…

CUlamek ulamek1(4,6);
CUlamek ulamek2(5);
//pobranie referencji
CUlamek suma = ulamek1 + ulamek2;
suma.wyswietl();

CUlamek&

CUlamek::operator+ (const CUlamek &n_ulamek) {

CUlamek tmp(

(this->m_iLicznik+n_ulamek.m_iLicznik),
(this->m_iMianownik+n_ulamek.m_iMianownik));

return tmp; }

9
7

L

M

4
6

L

M

5
1

L

M

=

+

suma

ulamek1

ulamek2

W przypadku operatorów

wartość lewa i prawa

muszą być identyczne

background image

itm / MVLab (c) 2007-2011

Dokładniej o operatorze
przypisania II

l

Obydwa obiekty istnieją – konieczne przypisanie

l

Musi być zgodność typów

l

Przeciążony operator "=" (głębokie kopiowanie)

3

możliwości implementacji

CUlamek ulamek1(4,6);
CUlamek ulamek2(17,4);

ulamek1 = ulamek2;
ulamek1.wyswietl();

CUlamek

CUlamek::operator= (const CUlamek &n_ulamek) {

if(this==&n_ulamek) //must avoid self destruction
//...
cout<<"assignment operator called";
this->m_iMianownik=n_ulamek.m_iMianownik;
this->m_iLicznik=n_ulamek.m_iLicznik;

CUlamek temp(this->m_iLicznik,this->m_iMianownik);
cout<<"assignment operator finished";
return temp;

}

background image

itm / MVLab (c) 2007-2011

Dokładniej o operatorze
przypisania II

l

Obydwa obiekty istnieją –konieczne przypisanie

l

Musi być zgodność typów

l

Przeciążony operator "=" (głębokie kopiowanie)

3

możliwości implementacji

CUlamek ulamek1(4,6);
CUlamek ulamek2(17,4);

ulamek1 = ulamek2;
ulamek1.wyswietl();

CUlamek

CUlamek::operator= (const CUlamek &n_ulamek) {

if(this==&n_ulamek) //must avoid self destruction
//...
cout<<"assignment operator called";
this->m_iMianownik=n_ulamek.m_iMianownik;
this->m_iLicznik=n_ulamek.m_iLicznik;

cout<<"assignment operator finished";

return CUlamek (this->m_iLicznik, this->m_iMianownik);

}

background image

itm / MVLab (c) 2007-2011

Dokładniej o operatorze
przypisania II

l

Obydwa obiekty istnieją –konieczne przypisanie

l

Musi być zgodność typów

l

Przeciążony operator "=" (głębokie kopiowanie)

3

możliwości implementacji

CUlamek ulamek1(4,6);
CUlamek ulamek2(17,4);

ulamek1 = ulamek2;
ulamek1.wyswietl();

CUlamek& CUlamek::operator =(const CUlamek& n_Ulamek)
{

if(this == &n_Ulamek) //must avoid self destruction

return *this;

cout << “assignment operator called“;
this->m_iLicznik = n_Ulamek.m_iLicznik;
this->m_iMianownik = n_Ulamek.m_iMianownik;
cout << "\nassignment operator finished\n";

return *this

; // wszystkie kopie zachowane

}

background image

itm / MVLab (c) 2007-2011

Co już było (w rozdz. 3 i 4)?

l

To już potrafimy:

l

implementacja klas niezależnie od ich późniejszego użycia

l

rozdział na deklaracje (header) oraz definicje i użycie
(implementacja)

l

stosowanie zasady information-hiding

l

implementacja operacji w postaci
metod i operatorów

l

To musimy sobie przypomnieć:

l

krok 1.: deklaracja
i implementacja klas,

l

krok 2.: zastosowanie
w konkretnym przypadku

l

Teraz chodzi nam o:

l

implementacja zależności pomiędzy klasami.

Rodzic

Potomek 1

Potomek 2

background image

itm / MVLab (c) 2007-2011

itm / MVLab (c) 2007-2008

4.4

Zależności między klasami

4.4.1

Relacje współpracy

Kompozycje

Agregacje

4.3.2 Relacje dziedziczenia

Asocjacje

Dziedziczenie proste

Dziedziczenie złożone

background image

itm / MVLab (c) 2007-2011

Relacje współpracy (asocjacje)

Asocjacja

, to rodzaj zależności

pomiędzy klasami.

Opisuje wspólną semantykę i strukturę

zbioru powiązań między obiektami.
Instancja asocjacji

(połączenie między obiektami klasy)

określa się jako link.

Cechy rozróżniające:

l

wg typu

l

kompozycja

l

agregacja

l

(prosta) asocjacja

l

wg kierunkowości

l

wg wielokrotności

Część zależna

Całość

Część

Całość

1

*

0..1

*

Klasa 2

Klasa 1

-nazwisko
-nr_umowy

Pracownik

-nazwa
-adres

Firma

1

*

-pracodawca -pracobiorca

zatrudniony

-ulica
-kod_poczt

Adres

-

wartość

-adres

Rachunek

*

1

ma

X

background image

itm / MVLab (c) 2007-2011

Kompozycja

Właściwości:

l

Kryterium: zachowanie danych

l

Kapsulacja części składowych

l

Zależność czasu życia

Część zależna

Całość

1

*

// Przykład kompozycji
//Calosc.h
class CCalosc {

private:

int m_wlasciwosc;
class CCzesc {

int m_a;
int m_b;

public:

CCzesc();
void test();

} m_drugaWlasciwosc;

};

// Przykład kompozycji
//Calosc.h
#include "Calosc.h"
CCalosc::CCzesc::CCzesc() {

m_a=0; m_b=0;

};
void CCalosc::CCzesc::test() {

m_a=1; m_b=1;

}

Zagnieżdżone deklaracje

klas i zmiennych wewnątrz

klasy zawierającej

background image

itm / MVLab (c) 2007-2011

Agregacja

Właściwości:

l

Kryterim: zachowanie danych

l

Klasy posługują się klasami

l

Zależność składa-się-z…

Część

Całość 2

0..1

*

// Przykład agregacja
// Osoba.h
#include "MyString.h"
class COsoba {

private:

CMyString m_imie;
CMyString m_nazwisko;

public:

//...
};

// Przykład agregacji
// main.cpp
#include "Calosc.h"
void main() {

COsoba Osoba1;
//...

}

Klasa COsoba posługuje się

obiektami innej klasy

jako właściwościami.

Całość 1

0..1

background image

itm / MVLab (c) 2007-2011

Osoba1

Agregacja:

Powoływanie obiektów

// Przykład agregacji
// main.cpp
#include "Calosc.h"
void main() {

COsoba Osoba1;
//...

}

0

NULL

imię

0

NULL

nazwisko

Osoba1

0

NULL

imię

0

NULL

nazwisko

Osoba1

0

NULL

imię

???

???

nazwisko

Osoba1

???

???

imię

???

???

nazwisko

Krok 1:

Alokacja pamięci

Krok 2: Konstruktor

domyślny dla imię

Krok 3: Konstruktor

domyślny dla nazwisko

Krok 4: Konstruktor

domyślny dla klasy
COsoba

Wywołanie konstruktorów

domyślnych komponentów
zagregowanych (w

kolejności deklaracji) –krok
2. i 3

. następuje przed

wywołaniem konstruktora
klasy.

background image

itm / MVLab (c) 2007-2011

Lista inicjalizacyjna

l

Klasy bez konstruktorów domyślnych nie mogą być agregowane

przez inne klasy (z wyjątkiem tych gdzie są zdefiniowane inne

konstruktory, ale nie domyślny.

l

Wywołanie konstruktora domyślnego elementu agregowanego jest

bezsensowne, jeśli konstruktor obiektu agregującego nadpisze dane.

// Osoba.h
#include "MyString.h"
Class COsoba {

public:

COsoba(CMyString& imie,

CMyString& nazwisko);

//...

void main() {

CMyString vn = "Marcin";
CMyString nn = "Wróbel";
COsoba ja(vn,nn);
//...

//

Osoba.cpp (ZŁA WERSJA!)

#include "Osoba.h"
COsoba::COsoba(CMyString& imie,

CMyString& nazwisko) {

m_nazwisko = nazwisko;
m_imie = imie;

};

ja

6

imię

6

nazwisko

Marcin

Wróbel

Krok 4: Konstruktor

główny nadpisuje ewent.

wartości wpisane przez

konstruktor domyślny

.

background image

itm / MVLab (c) 2007-2011

Lista inicjalizacyjna

Właściwości:

l

Pozwalają konstruktorom używanym do inicjalizacji komponentów

przekazywać argumenty przez wartość

l

Mogą zostać użyte tylko dla konstruktorów

Składnia:

l

Są wypisywane za listą argumentów funkcji, po dwukropku

l

Składają się z listy wyrażeń rozdzielanych przecinkiem, w postaci
komponent(argument);

// Osoba.cpp (wersja poprawiona)
#include "Osoba.h"
COsoba::COsoba(CMyString& imie, CMyString& nazwisko):

m_imie(imie), m_nazwisko(nazwisko)

{ // Nic więcej nie trzeba robić!
};

Dzięki takiej liście

nie będą uruchamiane domyślne

konstruktory klas zagregowanych,

lecz konstruktory kopiujące.

background image

itm / MVLab (c) 2007-2011

(Proste) Asocjacje

Właściwości:

l

Kryterim: zachowanie danych

l

Obiekty różnych klas „znają się”
nawzajem

l

Umożliwienie wywołania metod
obiektów innych klas

l

Cechy: kierunkowość i wielokrotność

Pomocy!! -

Już nie mogę....

l

uwzględnienie wszystkich aspektów

wyszłoby daleko poza nasze ramy

l

ograniczamy się wyłącznie na
asocjacjach 1:1, jedno- i
dwukierunkowych.

-ulica
-kod_poczt

Adres

-

wartość

-adres

Rachunek

*

1

ma

X

Nie umiem
pływać, nie
umiem pływać!!!

A ja chodzić, a
mimo to nie drę
się jak głupi na
całą okolicę...

background image

itm / MVLab (c) 2007-2011

Asocjacja -

przykład

Sytuacja:

l

Projektowana jest aplikacja do

obliczeń arytmetycznych, która

ma korzystać z obiektów klasy

ułamek.

l

„Zapoznanie” tych dwóch klas

ze sobą powinno się odbywać

w konstruktorze którejś z klas
programu obliczeniowego.

// Przykład asocjacji
// Arytm.h
#include "Ulamek.h"
class CArytm {

private:

CUlamek* p_ulamek;

public:

CArytm();
CArytm(CUlamek* p_ulamek);

//...

// Przykład asocjacji
// main.cpp
#include "Arytm.h"
void main() {

CUlamek ulamek1(2,3);
CArytm Ar1(&ulamek1);
//...

}

„Zapoznanie”

-licznik
-mianownik

Ulamek

Arytmetyka

0

1

zna

X

Asocjacja przez

wskaźnik na

obiekt zewnętrzny

background image

itm / MVLab (c) 2007-2011

Zaprzyjaźnienia (friend)

Wszystkie dotychczas omówione zależności wymagają

dostępu jednej klasy do metod drugiej. Co jednak, gdy

nie można tego zrealizować

Przykłady:

l

Operator dodawania zmiennej int i obiektu klasy CUlamek,

gdy int jest pierwszym operandem wymaga przeciążenia operatora+ dla typu
int.

l

Wyjście obiektu klasy CUlamek na strumień cout za pomocą standardowego

operatora << wymaga jego przeciążenia w klasie ostream (z niej pochodzi
obiekt cout).

Rozwiązanie:

l

Globalne definicje przeładowywanych funkcji jako funkcji zaprzyjaźnionych,

oznaczonych słowem kluczowym friend, dzięki czemu

mogą

one mieć dostęp

do prywatnych składników klas z którymi są zaprzyjaźnione.

ALE:

Każdy kij ma dwa końce! -kolizja z zasadą information-hiding.

CUlamek ulamek1(5,7);
Culamek ulamek2;
int liczba = 3;

ulamek2=liczba+ulamek1;

cout<<"Wynik: "<<ulamek2;

background image

itm / MVLab (c) 2007-2011

Zaprzyjaźnienia - przykład

Sytuacja:

l

chcemy umożliwić operację jak na przykładzie poniżej:

// main.cpp (Funkcje globalne)
ostream& operator<<(ostream& str, const CUlamek& ulamek) {

str << ulamek.m_iLicznik << "/" << ulamek.m_iMianownik;
return str;

}
//...
void main() //...

// CUlamek.h
class Culamek {
private:

int m_iLicznik, m_iMianownik;
friend ostream& operator<<(ostream&, const CUlamek&);

public:

//...

}

Dostęp do prywatnego

składnika klasy CUlamek.

Globalne przeciążenie operatora <<.

Zostanie przyjęte przez system

jeśli nie znajdzie się żaden

pasujący operator w klasie ostream.

cout << "Wartosc ulamka: "<< ulamek1 << endl;

W ten sposób funkcja

uzyska dostęp do prywatnych

składników klasy CUlamek.

background image

itm / MVLab (c) 2007-2011

Dziedziczenie

Dziedziczenie

l

podklasy (także klasy częściowe, klasy wyprowadzone i podklasy)

dziedziczą wszystkie właściwości i metody swoich klas bazowych.

l

mogą posiadać własne -niezależne od klas bazowych oraz innych

klas potomnych (rodzeństwa) składniki oraz modyfikować metody
odziedziczone.

l

zasada ponownego wykorzystania kodu.

Problemy

l

dziedziczenie proste vs

. dziedziczenie złożone

l

polimorfizm vs. funkcje wirtualne.

Rodzic

Potomek

background image

itm / MVLab (c) 2007-2011

Dziedziczenie proste

l

Specjalizacja klasy bazowej

l

Przykład: klasa CUlamekDzies specjalizujący

klasę CUlamek o możliwość definiowania

dokładności.

-Licznik: int
-Mianownik: int

Ulamek

-Dokladnosc: int

UlamekDzies

// Przykład dziedziczenia
// UlamekDzies.h
#include "Ulamek.h"
class CUlamekDzies: public CUlamek {

private:

int m_iDokladnosc;

public:

CUlamekDzies(int L, int M, int D);
void pokaz() const;

}

Wyrażenie

definiujące

dziedziczenie

Nowy konstruktor

(trójparametrowy)

Przedefiniowanie

(dopasowanie) metody

Nowy atrybut

background image

itm / MVLab (c) 2007-2011

Dziedziczenie proste -

przykład

// Przykład dziedziczenia
// UlamekDzies.h
#include "Ulamek.h"
class CUlamekDzies:

public CUlamek

{

private:

int m_iDokladnosc;

public:

CUlamekDzies
(int L, int M, int D);
void pokaz() const;

}

Poniższe przykłady nie należą do dobrego stylu programistycznego

i są przytoczone w tej postaci tylko dla jasności kodu.

// Przykład dziedziczenia
// UlamekDzies.cpp
#include "Ulamek.h"
#include <math.h>
CUlamekDzies::CUlamekDzies

(int iL, int iM, int iD) {

this->Zmien(pow(10,iD)*iL/iM,

pow(10,iD));

m_iDokladnosc=iD;

}
void CUlamekDzies::pokaz() const {

CUlamek::pokaz();
cout<<"Dokladnosc: "<<m_iDokladnosc;

}

#include "UlamekDzies.h"
void main() {

CUlamekDzies mojUlamekDzies(1,3,3);
mojUlamekDzies.pokaz();

}

Odziedziczona metoda

Jawne wywołanie

metody klasy zewnętrznej

background image

itm / MVLab (c) 2007-2011

Polimorfizm

l

dzięki polimorfizmowi możliwe jest wywoływanie metody obiektu bez
odgórnej wiedzy jakiej jest on klasy -

system sam ją określi i

spowoduje że na pewno zareaguje on na swój specyficzny sposób

l

dziedziczenie powoduje zachowania polimorficzne

#include "UlamekDzies.h"
void main() {

CUlamekDzies mojUlamekDzies(1,3,3);
CUlamek mojUlamek(2,5);
CUlamek *wynikUlamkowy;

//Przypadek 1

wynikUlamkowy = &mojUlamek;
wynikUlamkowy->pokaz();

//Przypadek 2

wynikUlamkowy = &mojUlamekDzies;

wynikUlamkowy->pokaz();

}

Niestety

nie pokaże tego

co chcemy

OK.

CUlamekDzies

jest przecież

również CUlamek

background image

itm / MVLab (c) 2007-2011

Polimorfizm i wirtualność

// Ulamek.h
#include <iostream>
using namespace std;

class CUlamek {

private:

int m_iLicznik;
int m_iMianownik;

public:

virtual void pokaz() const;
virtual ~CUlamek();

//...
};

#include "UlamekDzies.h"
void main() {

CUlamekDzies

mojUlamekDzies(1,3,3);

CUlamek mojUlamek(2,5);
CUlamek *wynikUlamkowy;

//Przypadek 1

wynikUlamkowy = &mojUlamek;
wynikUlamkowy->pokaz();

//Przypadek 2

wynikUlamkowy =

&mojUlamekDzies;

wynikUlamkowy->pokaz();

}

Słowo kluczowe virtual w pliku nagłówkowym

mówi o tym, że metoda klasy potomnej

może zostać nadpisana.

Szczególnie ważne: wirtualny destruktor!!

Dopasowanie metod w czasie działania

przez tzw. wirtualną tablicę metod.

Zalety: zachowuje się tak jak chcemy

Wady: utrata efektywności.

background image

itm / MVLab (c) 2007-2011

Przykład zastosowania:
Zdarzenia

+ ~DostZdarz()

DostawcaZdarzenia

+ DostZdarz(in Handl1: HandlZdarz&)

-Handler: HandlZdarz

DostawcaZdarzenia

+ HandlZdarz()
+ nowyAbonent(in Abnt: AbonentZdarz&)
+ usunAbonenta(in Abnt: AbonentZdarz&)
+ odklejOdZdarz(in Dost: DostZdarz&)

-Ilosc: int
-Abonamenty: wektor<AbonentZdarz*>

HandlerZdarzenia

DataChangedHandler

+ OnZdarzenie(in Dost: DostZdarz&): bool

AbonentZdarzenia

+ OnZdarzenie(in Dost: DostZdarz&): bool

Wizualizacja

background image

itm / MVLab (c) 2007-2011

Powtórka i podsumowanie
rozdz. 4.4

•Kompozycje
•Agregacje
•Asocjacje

Klasy używają klas

Zależność „has-a”

Inne zależności

Zależność „is-a”

•Dopasowywanie i
rozszerzanie dziedziczonej

funkcjonalności

•Dziedziczenie proste
•(Dziedziczenie
wielokrotne)

Zależności między klasami

Zaprzyjaźnienia

(friends)

listy inicjalizacyjne

polimorfizm

wirtualność

background image

itm / MVLab (c) 2007-2011

Czego zabrakło - rozdział 4.5

4.1

Zanim rozpoczniemy implementację...

4.2 Pierwsze kroki w kierunku

programowania w C++

4.3

Klasy „rosną”...

4.4

Zależności pomiędzy klasami

4.5

Implementacja rozwiązań

(w następnym semestrze)

Kiedy przećwiczymy podstawy

będziemy programować

pierwsze aplikacje obiektpwe w c++


Document Outline


Wyszukiwarka

Podobne podstrony:
gs w07 id 197504 Nieznany
KZ BD w07 id 256666 Nieznany
gs w07 id 197504 Nieznany
al1 w07 zima2011 id 54569 Nieznany (2)
Lab 2 pdt w07 info id 749435 Nieznany
Bazy danych w07 07 id 81703 Nieznany
Abolicja podatkowa id 50334 Nieznany (2)
4 LIDER MENEDZER id 37733 Nieznany (2)
katechezy MB id 233498 Nieznany
metro sciaga id 296943 Nieznany
perf id 354744 Nieznany
interbase id 92028 Nieznany
Mbaku id 289860 Nieznany
Probiotyki antybiotyki id 66316 Nieznany
miedziowanie cz 2 id 113259 Nieznany
LTC1729 id 273494 Nieznany
D11B7AOver0400 id 130434 Nieznany
analiza ryzyka bio id 61320 Nieznany

więcej podobnych podstron