Wersja 2013-04
Wersja 2013-04
Zaawansowane techniki
programowania
Składnia C++
Składnia C++
Człowiek- najlepsza inwestycja
Zaawansowane techniki programowania
Szablony
vð
Funkcje uogólnione
" Często spotyka się funkcje (algorytmy), które można zastosować do
szerokiej klasy typów i struktur danych. Typowym przykładem jest
funkcja obliczająca maksimum dwu wartości:
int max(int a, int b) {return (a>b)?a:b;};
int max(int a, int b) {return (a>b)?a:b;};
double max(double a,double b) {return (a>b)?a:b;};
double max(double a,double b) {return (a>b)?a:b;};
string max(string a,string b) {return (a>b)?a:b;};
string max(string a,string b) {return (a>b)?a:b;};
skorzystaliśmy tu z dostępnej w C++ możliwości przeładowywania funkcji
skorzystaliśmy tu z dostępnej w C++ możliwości przeładowywania funkcji
main() {
main() {
cout<< max(7,5)<
cout<< max(7,5)<cout<< max(3.1415,2.71)<cout<< max(3.1415,2.71)<cout<< max("Ania","Basia")<cout<< max("Ania","Basia")<}}
Zaawansowane techniki programowania
Co będzie na wykładzie
vð
Składnia C / C++, programowanie obiektowe
«%
Typy danych, instrukcje oraz ich specyfika
«%
Programowanie obiektowe dziedziczenie i polimorfizm.
«%
Abstrakcja danych i metod, pojęcie interfejsu. Tworzenie i
destrukcja zmiennych polimorficznych. Zarządzanie pamięcią.
«%
Operatory jak i kiedy zmieniać ich działanie? Niebezpieczeństwo
zmiany zachowań.
«%
Rzutowania typów rodzaje i wykorzystanie.
«%
Przestrzenie nazw
«%
Asercje co to jest i do czego stosować.
«%
Wyjątki i reakcje na błędne sytuacje.
«%
Dziedziczenie wielokrotne, konflikty.
«%
Ukryte działania kompilatorów, kolejność wywołań konstruktorów i
destruktorów.
Zaawansowane techniki programowania
Co będzie na wykładzie
vð
Programowanie generyczne (metaprogramowanie).
żð
Kiedy to potrzebne i czym różni się od programowania
obiektowego.
żð
Szablony funkcji
żð
Szablony klas
żð
Pozatypowe parametry szablonów
żð
Konkretyzacja
żð
Polimorfizm szablonów
żð
Inteligentne wskazniki, krotki, obiekty funkcyjne.
vð
Algorytmy i kontenery biblioteki STL.
żð
Praktyczne przykłady zastosowań.
żð
Biblioteka BOOST.
Zaawansowane techniki programowania
Co będzie na wykładzie
vð
Programowanie wielowÄ…tkowe / wieloprocesowe
«%
Podstawy synchronizacja, pojęcia, struktury programistyczne
«%
Implementacja dla win / linux
«%
Zakleszczenia, głodzenie, wywłaszczanie, zabijanie
Zaawansowane techniki programowania
Co będzie na wykładzie
vð
Budowa elastycznego oprogramowania.
żð
Biblioteki dołączane dynamicznie.
żð
Rodzaje i metody budowy wtyczek. Manager wtyczek.
żð
Automatyczna kompilacja kodu C++ z poziomu użytkownika
aplikacji.
żð
Połączenia z innymi językami programowania.
żð
Osadzanie skryptów we własnej aplikacji.
Zaawansowane techniki programowania
Co będzie na wykładzie
vð
Programowanie sieci
żð
Podstawy serwer / klient, TCP/IP, gniazda
żð
Implementacja w API dla win / linux
żð
Implementacja bardziej wysokopoziomowa
żð
Szyfrowanie i zabezpieczanie komunikacji sieciowej
Zaawansowane techniki programowania
Literatura
żð
Bjarne Stroustrup Język C++ wydanie 2, PWN
żð
Victor Shtren Core C++ Inżynieria oprogramowania , Helion
żð
Jesse Liberty C++ Księga eksperta , Helion
żð
David Vandevoorde, Nicolai Josuttis C++ Szablony , Helion
żð
Andrew S. Tanenbaum, Maarten van Steen Systemy
rozproszone. Zasady i paradygmaty , PWN
żð
Scott Meyers STL w praktyce , Helion
żð
Bjorn Karlsson Więcej niż C++. Wprowadzenie do bibliotek
Boost , Helion
żð
Seria ........ Vademecum profesjonalisty , Helion
Zaawansowane techniki programowania
Język C++ - to co powinniście znać
vð
Programowanie strukturalne
«%
Jedno z najstarszych podejść
«%
Opiera się głównie na procedurach struktury danych
wynikają z potrzeb algorytmów
«%
Wymaga instrukcji warunkowych i pętli (C++ to ma)
vð
Programowanie modularne
«%
Krok dalej
«%
Niezależnie kompilowane jednostki
«%
Przestrzenie nazw pozwalają unikać nadpisywania
zmiennych i funkcji
Zaawansowane techniki programowania
Język C++ - to co powinniście znać
vð
Programowanie obiektowe
żð
Sami tworzymy typy danych
«% Typ danych szablon bytu, który jest opisywany poprzez pewne
wartości, oraz na którym można wykonać pewne operacje.
«% W C++ jest nazywany klasÄ…
«% Klasa to szablon nie konkretny obiekt
«% Instancja typu konkretyzacja szablonu to obiekt.
żð
To samo tylko inaczej:
«% Modele skÅ‚adajÄ… siÄ™ z obiektów, które wchodzÄ… w interakcje,
przesyłając sobie nawzajem komunikaty. Wyobrazcie sobie obiekt
jako żywą istotę. Obiekty mają coś, co wiedzą (atrybuty), oraz coś,
co mogą zrobić (zachowania lub operacje). Wartości atrybutów
obiektu określają jego stan.
«% Klasy to "plany" obiektów. Klasa Å‚Ä…czy atrybuty (dane) oraz zachowania
(metody lub funkcje) w jedną odrębną jednostkę.
«% Obiekty sÄ… egzemplarzami (instancjami) klas.
Zaawansowane techniki programowania
Składnia C++
Pliki dołączane
vð
Struktura
#include
#include
#include
#include
Definicja zmiennych
using namespace std; globalnych
using namespace std;
Nagłówek funkcji
int globalna;
int globalna;
/* Nasz właściwy program zaczyna się tutaj */
/* Nasz właściwy program zaczyna się tutaj */
int main(int argc, char *argv[])
int main(int argc, char *argv[])
{{
cout << "Start" << endl;
cout << "Start" << endl;
int x, y, z, w;
int x, y, z, w;
cin >> x >> y >> z; // wczytaj wartości danych o nazwach x, y, x
cin >> x >> y >> z; // wczytaj wartości danych o nazwach x, y, x
w = (x+y)*(x-z); // oblicz wartość wyrażenia i nazwij je w
w = (x+y)*(x-z); // oblicz wartość wyrażenia i nazwij je w
cout << w << endl; // wypisz na ekranie wartość danej o nazwie w
cout << w << endl; // wypisz na ekranie wartość danej o nazwie w
return 0;
return 0;
}}
Ciało funkcji
Zaawansowane techniki programowania
Składnia C++
/* Zwyczajowo na początku zamieszcza się dołączane nagłówki (domyślnie C++ nie dołącza
/* Zwyczajowo na początku zamieszcza się dołączane nagłówki (domyślnie C++ nie dołącza
nic) bibliotek i dyrektywy preprocesora (czyli linie zaczynajÄ…ce siÄ™ od #).
nic) bibliotek i dyrektywy preprocesora (czyli linie zaczynajÄ…ce siÄ™ od #).
*/
*/
#include
#include
#include
#include
#include
#include
/* Wygodne choć może mało eleganckie */
/* Wygodne choć może mało eleganckie */
using namespace std;
using namespace std;
/* Program zapisuje się w C++ w postaci funkcji. Każda funkcja zaczyna się nagłówkiem,
/* Program zapisuje się w C++ w postaci funkcji. Każda funkcja zaczyna się nagłówkiem,
potem występuje treść zamknięta w nawiasy klamrowe. Program może składać się z
potem występuje treść zamknięta w nawiasy klamrowe. Program może składać się z
wielu funkcji. Zawsze musi być co najmniej jedna - main
wielu funkcji. Zawsze musi być co najmniej jedna - main
*/
*/
typ_zwracanej_wartości nazwa_funkcji(lista_parametrow)
typ_zwracanej_wartości nazwa_funkcji(lista_parametrow)
{{
...
...
};
};
Zaawansowane techniki programowania
Składnia C++
/* Przed lub pomiędzy funkcjami zamieszcza się definicje i deklaracje stałych,
/* Przed lub pomiędzy funkcjami zamieszcza się definicje i deklaracje stałych,
zmiennych, typów i klas globalnych dla danego pliku */
zmiennych, typów i klas globalnych dla danego pliku */
const int...{definicja stałych}
const int...{definicja stałych}
...
...
typedef...{definicja typów}
typedef...{definicja typów}
...
...
double... {definicja zmiennych}
double... {definicja zmiennych}
...
...
/* W każdym programie C++ jest jedna główna funkcja main albo WinMain */
/* W każdym programie C++ jest jedna główna funkcja main albo WinMain */
int main(int argc, char *argv[])
int main(int argc, char *argv[])
/* Nawiasy klamrowe służą do oznaczenia początku i końca funkcji */
/* Nawiasy klamrowe służą do oznaczenia początku i końca funkcji */
{{
instrukcja;
instrukcja;
instrukcja;
instrukcja;
...
...
instrukcja;
instrukcja;
/* W C++ pomiędzy instrukcjami znów mogą się znalezć definicje
/* W C++ pomiędzy instrukcjami znów mogą się znalezć definicje
zmiennych, typów, stałych - lecz w takim wypadku będą one lokalne */
zmiennych, typów, stałych - lecz w takim wypadku będą one lokalne */
} /* ZamykajÄ…cy nawias klamrowy */
} /* ZamykajÄ…cy nawias klamrowy */
Zaawansowane techniki programowania
Składnia C++
żð
Mało restrykcyjny jeśli chodzi o
wyglÄ…d kodu
«% Każda instrukcja koÅ„czy siÄ™
średnikiem
«% BiaÅ‚e znaki sÅ‚użą do oddzielania
elementów języka od siebie
żð
Dwa typy komentarzy:
«% Od znaku // do koÅ„ca linii
«% Od znaków /* do napotkania
odpowiedniej pary */
«% Jedne można zagnieżdżać w
drugich
żð
Formatowanie kodu:
«% Eleganckie
«% Bloki zawsze wciÄ™te
Zaawansowane techniki programowania
Składnia C++
ANSI Kernighan GNU Moje ?
namespace foospace
namespace foospace { namespace foospace
namespace foospace
{
class Bar {
{
{
class Bar
public:
class Bar
class Bar
{
{
int foo();
{ public:
private: public:
int foo();
public:
int foo();
int foo_2();
private:
}; private:
int foo();
int foo_2();
int foo_2();
private:
};
int Bar::foo() { };
int foo_2();
switch (x) {
}; int Bar::foo()
case 1: int Bar::foo()
{
a++;
{
switch (x)
break; switch (x)
int Bar::foo()
{
{
default: break;
{
case 1:
case 1:
}
switch (x)
a++;
a++;
if (isBar) {
break;
{
bar(); break;
default:
return m_foo+1; default:
case 1:
break;
break;
} else
a++;
}
return 0; }
break;
if (isBar) {
} if (isBar)
default:
bar();
} {
break; return m_foo+1;
bar();
} else
return m_foo+1;
}
return 0;
}
if (isBar)
}
else
{
}
return 0;
bar();
}
return m_foo+1;
}
}
else
return 0;
}
}
Zaawansowane techniki programowania
Składnia C++
vð
Typy
x = y + f(2);
«% W C++ by to miaÅ‚o sens x, y i f muszÄ… być odpowiednio
zadeklarowane (by stały się bytami o swoich nazwach)
«% Z każdÄ… nazwÄ… (identyfikatorem) jest zwiÄ…zany typ.
«% Typ okreÅ›la jakie operacje można wykonać na jego
przedstawicielu
«% StaÅ‚e można odczytać ich wartość
«% Zmienne można odczytać i zapisać
«% Funkcje można wykonać.
«% Klasy, szablony, przestrzenie nazw na to przyjdzie pora...
Zaawansowane techniki programowania
Składnia C++
// poprawne zmienne:
// poprawne zmienne:
żð
Co jest identyfikatorem w C++:
int Aaa, aAa, aaa;
int Aaa, aAa, aaa;
«% identyfikator: double _kot, mi29, Moja1B_;
double _kot, mi29, Moja1B_;
" niecyfra
// niepoprawnie
// niepoprawnie
" identyfikator niecyfra
char ala ma kota;
char ala ma kota;
bool 39A;
" identyfikator cyfra
bool 39A;
double new;
double new;
«% W skrócie:
float $inna_zmienna;
float $inna_zmienna;
::=
// definicja zmiennej
{|}
// definicja zmiennej
double zmienna;
double zmienna;
«% niecyfra: litera Å‚aciÅ„ska lub _
// deklaracja
// deklaracja
żð
Słowa kluczowe są zastrzeżone
extern double inna;
extern double inna;
żð
Wielkość liter ma znaczenie
Zaawansowane techniki programowania
Składnia C++
Przeliczalne
vð
Typy podstawowe:
(całościowe)
żð
Ściśle powiązane ze sprzętem
«% Logiczne
«% Znakowe
«% CaÅ‚kowite
«% Zmiennoprzecinkowe
żð
Wyliczeniowe
Arytmetyczne
żð
Typ oznaczający brak wartości
żð
Pochodne
«% Tablice
«% Wskazniki i referencje
«% Struktury i klasy
Zaawansowane techniki programowania
Składnia C++
vð
Typy zmiennopozycyjne
żð
float, double, long double:
double da = 1.23;
double da = 1.23;
«% Korzystajcie z double.
double db = .23;
double db = .23;
double dc = 1.;
double dc = 1.;
«% Przypisujemy wartoÅ›ci korzystajÄ…c z literałów
double dd = 1.2e-12;
double dd = 1.2e-12;
zmiennoprzecinkowych
" F, f, L, l przyrostek definiujący sposób traktowania
literału
«% Zakres i liczba bajtów zależna od implementacji
«% Stosujmy numeric_limits.
cout << "float \t-> r " << sizeof(float);
cout << "float \t-> r " << sizeof(float);
cout << " <" << numeric_limits::min();
cout << " <" << numeric_limits::min();
cout << "; " << numeric_limits::max() << ">\n";
cout << "; " << numeric_limits::max() << ">\n";
vð
Typ void
«% Nie ma takich obiektów
«% Oznacza że coÅ› nie ma wartoÅ›ci
Zaawansowane techniki programowania
Składnia C++
vð
Typ logiczny bool
«% Dwie wartoÅ›ci prawda i faÅ‚sz.
«% Nie jest pamiÄ™tany w pojedynczym bicie
zajmuje bajt !
bool a, b = true;
bool a, b = true;
«% Przy rzutowaniu z innych typów Ò! 0 to faÅ‚sz,
bool c = -2;
bool c = -2;
wszystko inne prawda
bool d = c == b;
bool d = c == b;
bool e = c+b;
bool e = c+b;
«% PrzeksztaÅ‚cenie na liczbÄ™ caÅ‚kowitÄ… true Ò! 1,
bool f = c|f;
bool f = c|f;
false Ò! 0
char z1 = 'a'
char z1 = 'a'
«% Można stosować operacje arytmetyczne i logiczne
char z2= '\t'
char z2= '\t'
char z3 = 48;
vð char z3 = 48;
Typ znakowy char (wchar_t)
«% Jeden bajt (dwa dla wchar_t)
wchar_t wz = L'ab';
wchar_t wz = L'ab';
«% Wartość przypisujemy podajÄ…c literaÅ‚ lub kod znaku
«% Znaki ASCII 0-127 to standard, reszta zależy od
implementacji
«% Można stosować operacje arytmetyczne i logiczne
Zaawansowane techniki programowania
Składnia C++
vð
Typy całkowite
żð
int z modyfikatorami:
«% short, long wielkość zmiennej (uwaga nie
muszą się różnić!)
«% 1 = sizeof(char) <= sizeof(short) <= sizeof(int)
<= sizeof(long)
«% signed, unsigned sposób traktowania
najstarszego bitu
«% Do obliczeÅ„ zawsze lepiej signed.
«% Deklaracja int Ò! signed int bez modyfikatorów
długości
«% Przypisujemy wartoÅ›ci korzystajÄ…c z literałów
całkowitych.
" Dziesiętnie 0 2 83
" Ósemkowo 00 02 0123
" Szesnastkowo 0x0 0x2 0x53
" U, L mówi w sposób jawny bez znaku, długa
Zaawansowane techniki programowania
Składnia C++
vð
Wyliczenia
«% Przechowuje zbiór wartoÅ›ci
podanych przez użytkownika
// wyliczenie nienazwane
// wyliczenie nienazwane
enum {ala, kot, dwa_koty };
enum {ala, kot, dwa_koty };
«% Każde wyliczenie jest oddzielnym
// wyliczenie nazwane
// wyliczenie nazwane
typem
enum asta {la, vista };
enum asta {la, vista };
«% Może ale nie musi mieć nazwÄ™
// wyliczenie z określonym
// wyliczenie z określonym
«% Wyliczenia sÄ… nazwanymi staÅ‚ymi
// zakresem
// zakresem
całkowitymi
enum eee {aaa = 3, zzz = 9 };
enum eee {aaa = 3, zzz = 9 };
«% PrzeksztaÅ‚cenia w obie strony
eee zmienna = eee(3); // ok
eee zmienna = eee(3); // ok
«% Wynik przeksztaÅ‚cenia staÅ‚ej eee zmienna = eee(101); // zle
eee zmienna = eee(101); // zle
liczbowej spoza zakresu jest
typedef int calkowita;
typedef int calkowita;
niezdefiniowany
calkowita moja = 1;
calkowita moja = 1;
vð
Deklaracja synonimu nazwy
«% typedef sÅ‚owo kluczowe
Zaawansowane techniki programowania
Składnia C++
char znak;
char znak;
vð
Deklaracje i definicje stałych i
string s;
string s;
int licz = 1;
int licz = 1;
zmiennych
const double pi = 3.14;
const double pi = 3.14;
extern long pid;
extern long pid;
żð
Rozróżniamy definicję i deklarację
char *imie = "Alicja";
char *imie = "Alicja";
«% Definicja Ò! deklaracja, odwrotnie już nie
char *pora[] = {"wiosna",
char *pora[] = {"wiosna",
"lato",
"lato",
żð
Wszystko (stałe, zmienne, funkcje, itp) musi
"jesien",
"jesien",
"zima"}
mieć typ.
"zima"}
// dobrze
żð
Dla każdej nazwy musi istnieć tylko jedna
// dobrze
extern int licznik;
extern int licznik;
definicja
int licznik;
int licznik;
extern int licznik;
extern int licznik;
żð
Każda deklaracja składa się z czterech części:
// zle
// zle
«% Opcjonalny specyfikator
extern double licznik;
extern double licznik;
double licznik;
double licznik;
«% Typ
int licznik;
int licznik;
«% Deklarator (trochÄ™ szerzej niż nazwa)
int x, y;
int x, y;
«% Opcjonalny inicjalizator
int a1 = 2, b1;
int a1 = 2, b1;
long int *pole = NULL;
long int *pole = NULL;
int* p2, p3;
int* p2, p3;
Zaawansowane techniki programowania
Składnia C++
int x;
int x;
vð
Zasięg
int main(int argc, char *argv[])
int main(int argc, char *argv[])
żð
Każda nazwa może być
{{
int x = 1;
int x = 1;
wykorzystywana jedynie w części
{{
programu tam gdzie jest znana.
int x = 2;
int x = 2;
żð
ObowiÄ…zuje zasada predeklaracji
cout << x << endl;
cout << x << endl;
żð
Widoczność
// globalne x
// globalne x
::x = x + 2;
::x = x + 2;
«% Globalna widoczne od miejsca
}}
cout << x << endl;
cout << x << endl;
deklaracji do końca pliku. Globalnie
widoczne sÄ… nazwy deklarowane poza
cout << ::x << endl;
cout << ::x << endl;
funkcjÄ…, klasÄ… i przestrzeniÄ… nazw.
{{
«% Lokalna wewnÄ…trz bloku { }
// totalnie zle
// totalnie zle
int x = x;
int x = x;
«% WewnÄ…trz przestrzeni nazw
}}
}}
«% WewnÄ…trz klasy
void f()
void f()
żð
Działa przysłanianie nazw
{{
int y = x;
int y = x;
int x = 22;
int x = 22;
y = x;
y = x;
}}
Zaawansowane techniki programowania
Składnia C++
int x;
int x;
vð
Inicjacja zmiennych
int x2 = 4;
int x2 = 4;
char a='a';
char a='a';
«% JeÅ›li siÄ™ poda inicjator zostanie on
przypisany. const int sa = 1;
const int sa = 1;
const int sb = sa+1;
const int sb = sa+1;
«% Dla staÅ‚ych wartość inicjatora musi być
// zle
znana na etapie kompilacji // zle
const int sc = x+1;
const int sc = x+1;
«% Zmienne globalne, z przestrzeni nazw i
statyczne są inicjowane domyślną
int main(int argc, char *argv[])
int main(int argc, char *argv[])
wartością (dla typów podstawowych jest
{{
int y;
int y;
to 0)
static int z;
static int z;
}}
«% PozostaÅ‚e zmienne majÄ… wartość
przypadkową (uwaga może być
void f()
void f()
{{
niepoprawna!)
int y = x;
int y = x;
int x = 22;
int x = 22;
y = x;
y = x;
}}
Zaawansowane techniki programowania
Składnia C++
int x;
int x;
vð
Czas życia
int main(int argc, char *argv[])
int main(int argc, char *argv[])
żð
Wszystkie zmienne które teraz
{{
int x = 1;
int x = 1;
omawiamy sÄ… nazywane statycznymi i
{{
sÄ… alokowane na stosie.
int x = 2;
int x = 2;
żð
Zmienne globalne sÄ… inicjowane przed
cout << x << endl;
cout << x << endl;
uruchomieniem, kasowane po
// globalne x
// globalne x
::x = x + 2;
zakończeniu programu ::x = x + 2;
}}
cout << x << endl;
żð
Zmienne lokalne sÄ… tworzone w
cout << x << endl;
momencie definicji, natomiast
cout << ::x << endl;
cout << ::x << endl;
kasowane w momencie opuszczenia
{{
// totalnie zle
zasięgu.
// totalnie zle
int x = x;
int x = x;
}}
żð
Zarządzanie czasem życia zmiennych
}}
statycznych jest w pełni
void f()
void f()
automatyczne (nie mieszajmy siÄ™ do
{{
int y = x;
tego).
int y = x;
int x = 22;
int x = 22;
y = x;
y = x;
}}
Zaawansowane techniki programowania
Składnia C++
vð
Stałe
const int c1 = 1;
const int c1 = 1;
«% Definiowane poprzez sÅ‚owo kluczowe
const int c2 = 2;
const int c2 = 2;
const
«% const jest przedrostkiem przed nazwÄ…
const int c3 = moja_fun(3);
const int c3 = moja_fun(3);
const int* p = &c2;
dowolnej zmiennej i przekształca ją w
const int* p = &c2;
wartość stałą
«% Uniemożliwia zmianÄ™ wartoÅ›ci w zasiÄ™gu
widoczności bez jawnego rzutowania
«% DziÄ™ki optymalizacji czÄ™sto nie jest
konieczne przydzielanie pamięci z
obszaru pamięci danych dla stałych
vð
L-wartości
«% Wszystko co może stać po lewej stronie
przypisania czemu można przypisać
wartość.
«% W praktyce zmienne bez modyfikatora
const.
Zaawansowane techniki programowania
Składnia C++
vð
Wskazniki
char c = 'a';
char c = 'a';
char *p = &c;
char *p = &c;
żð
Zmienna wskaznikowa
int *pInt;
przechowuje w pamięci adres
int *pInt;
int **ppInt;
int **ppInt;
elementu danego typu (nie sam
int *pInt[10];
int *pInt[10];
element)
int ***pppInt;
int ***pppInt;
żð
Sama zmienna wskaznikowa w
rzeczywistości jest 4-bajtową int (*fp)(int *p);
int (*fp)(int *p);
void (*SetMes)(void *_func);
void (*SetMes)(void *_func);
zmiennÄ… statycznÄ…
żð
Można tworzyć wskazniki do
wskazników
żð
Można tworzyć wskazniki do
obiektów i funkcji c
'a'
żð
Wskaznik donikÄ…d to NULL lub
p
po prostu 0
&c
żð
const int NULL=0;
Zaawansowane techniki programowania
Składnia C++
int s1 = 5, s2 = 2;
int s1 = 5, s2 = 2;
int *p1, *p2;
int *p1, *p2;
vð
Arytmetyka wskazników
«% W C++ wskazniki można do siebie
p1 = &s1;
p1 = &s1;
p2 = &s2;
dodawać, wykorzystywać jako
p2 = &s2;
przełącznik w instrukcji switch,
cout << p1 << "\t" << *p1
cout << p1 << "\t" << *p1
mnożyć, inkrementować itd.
cout << endl;
cout << endl;
«% Należy zawsze wiedzieć co siÄ™ robi!
// zle !
// zle !
// p1++;
«% Nie ma kontroli poprawnoÅ›ci
// p1++;
// *p1++;
// *p1++;
wskaznika i obszaru pamięci
(*p1)++;
(*p1)++;
pokazywanego przez niego.
cout << s1 << endl;
cout << s1 << endl;
«% Dynamiczna alokacja new
s2 = *p1;
«% Zwalnianie pamiÄ™ci delete
s2 = *p1;
s2++;
s2++;
«% Wskaznik do void pozwala na
cout << s1 << "\t" << s2;
cout << s1 << "\t" << s2;
porównywanie adresów zmiennych
cout <<"\t"<< *p1 << endl;
cout <<"\t"<< *p1 << endl;
dowolnego typu, rzutować zmienne, i
przekazywać dowolne struktury
p2 = new int;
p2 = new int;
danych i funkcje między
delete p2;
delete p2;
// zle !
podprogramami
// zle !
// delete p1;
// delete p1;
Zaawansowane techniki programowania
Składnia C++
vð
Wskazniki i stałe
żð
W pracy ze wskaznikiem zawsze
char a, b;
char a, b;
mamy do czynienia z dwoma
// stały wskaznik do znaku
// stały wskaznik do znaku
char *const cp = &a;
char *const cp = &a;
zmiennymi samym
// wskaznik do stałego znaku
// wskaznik do stałego znaku
wskaznikiem i zmiennÄ…
char const* cp;
char const* cp;
const char* cp;
wskazywanÄ…
const char* cp;
żð
Samo const czyni wskazywany
// stały do stałego
// stały do stałego
const char *const cp = &a;
const char *const cp = &a;
obiekt stałym
żð
*const stały jest wskaznik
char n[] = "czem";
char n[] = "czem";
const char *p = n;
const char *p = n;
żð
Przydatne głównie do
definiowania argumentów // zle
// zle
p[1] = 'a';
p[1] = 'a';
funkcji
// dobrze
// dobrze
p = &b
p = &b
Zaawansowane techniki programowania
Referencje
vð
Referencja jest innÄ… nazwÄ… obiektu
«% Wykorzystywana głównie do
specyfikowania argumentów funkcji
int s1 = 5, s2;
int s1 = 5, s2;
int& r1 = s1;
int& r1 = s1;
(przeciążanie operatorów)
«% Musi zostać zainicjowana
s2 = r1;
s2 = r1;
r1 = 6;
r1 = 6;
«% Operatory zawsze dziaÅ‚ajÄ… na wartoÅ›ci
r1++;
r1++;
nigdy na referencji
// zle !
«% Można jÄ… traktować jako staÅ‚y wskaznik z
// zle !
int& r3 = 1;
int& r3 = 1;
niejawnym operatorem adresowania
int& r4;
int& r4;
pośredniego
// dobrze
«% Optymalizacja we współczesnych
// dobrze
extern int& r2;
extern int& r2;
kompilatorach często prowadzi do
const double& r5=1;
const double& r5=1;
usunięcia obiektów reprezentujących
referencje
«% StaÅ‚a referencja nie musi być inicjowana
l-wartością.
Zaawansowane techniki programowania
Składnia C++
vð
Tablice
żð
Ciągły obszar pamięci na n
jednakowych elementów
żð float v[3];
Indeksowany od 0 do n-1;
float v[3];
char *a[5];
char *a[5];
żð
Tablice statyczne muszą mieć rozmiar
int d2[2][10];
int d2[2][10];
int d3[2][2][2];
znany na etapie kompilacji int d3[2][2][2];
żð
Inicjowanie:
int v1[] = { 1, 2, 3, 4, 5 };
int v1[] = { 1, 2, 3, 4, 5 };
«% Poprzez listÄ™ wartoÅ›ci (bez rozmiaru)
int v2[10] = {1, 2};
int v2[10] = {1, 2};
«% Z rozmiarem
«% DopeÅ‚nia siÄ™ zerami
int *pInt = v1;
int *pInt = v1;
żð
Uwaga tablic w C++ nie powinno siÄ™
kopiować bezpośrednio i brak kontroli
int l = v1[0];
int l = v1[0];
zakresów
żð
Wskazniki i tablice w C++ są ściśle
powiÄ…zane
Zaawansowane techniki programowania
Składnia C++
vð
Tablice
int d2[2][10];
int d2[2][10];
int **d3;
«% Statyczne tablice wielowymiarowe int **d3;
także są jednolitym obszarem
// zle !
// zle !
pamięci
d2 = d3
d2 = d3
«% Tablice do funkcji nigdy nie sÄ…
for (int i=0; v[i]!=0; i++)
for (int i=0; v[i]!=0; i++)
przekazywane przez wartość
moja_f(v[i]);
moja_f(v[i]);
«% JeÅ›li chcemy by wartoÅ›ci w tablicy
for (char* p=v; *p!=0; p++)
for (char* p=v; *p!=0; p++)
nie mogły być zmienione przez
moja_f(*p);
moja_f(*p);
funkcję musimy korzystać z const
«% Korzystanie z tablic jest możliwe // dynamiczne tworzenie
// dynamiczne tworzenie
double **a;
double **a;
zarówno poprzez operator
indeksowania jak i operator [] - oba
a = new double[w];
a = new double[w];
sposoby teraz powinny być tak
for (int i=0; ifor (int i=0; ia[i] = new double[k];
samo szybkie
a[i] = new double[k];
...
...
«% Dynamiczne tworzenie tablic
a[i][j] = 1.5;
a[i][j] = 1.5;
operator new z rozmiarem w
...
...
for (int i=0; inawiasach kwadratowych
for (int i=0; idelete[] a[i];
delete[] a[i];
«% Usuwanie - delete[]
delete[] a;
delete[] a;
Zaawansowane techniki programowania
Składnia C++
vð
Napisy
// mozna zmieniac
żð
Nie istnieje wbudowany napisowy
// mozna zmieniac
char n1[] = "Ala ma kota";
char n1[] = "Ala ma kota";
typ zmiennej
// nie mozna zmieniac
// nie mozna zmieniac
char *n2 = "Ala ma kota";
żð char *n2 = "Ala ma kota";
Mamy w zamian tablicę znaków
zakończoną zerem (literał '\0')
// ok
// ok
n1[1] = 'a';
n1[1] = 'a';
żð
Funkcje do obsługi napisów
// zachowanie niezdefiniowane
// zachowanie niezdefiniowane
biblioteka string
n2[1] = 'a';
n2[1] = 'a';
żð
W miejsce klasycznych napisów
#include
#include
polecam klasÄ™ string z biblioteki
std::string t="Ala ma kota";
std::string t="Ala ma kota";
STL
// dlugosc napisu
// dlugosc napisu
t.size();
t.size();
reverse(s.begin(), s.end());
reverse(s.begin(), s.end());
Zaawansowane techniki programowania
Składnia C++
vð
Struktury
// struktura nazwana
// struktura nazwana
«% Zbiór elementów, które mogÄ… różnić siÄ™
struct costam {
struct costam {
typem
int a;
int a;
char b;
char b;
«% Za definicjÄ… musi znajdować siÄ™ Å›rednik
double c;
double c;
«% Można dowolnie mieszać struktury i
} ct1;
} ct1;
tablice i osadzać na dowolną głębokość
costam ct2, ct3 =
costam ct2, ct3 =
«% DomyÅ›lnie dla każdej struktury zostanie
{ 10, 'a', 3.5 };
{ 10, 'a', 3.5 };
automatycznie wygenerowany operator
// struktura nienazwana
przypisania i konstruktor kopiujÄ…cy
// struktura nienazwana
struct {
struct {
«% Wynik dziaÅ‚ania pozostaÅ‚ych operatorów
int a1, a2;
int a1, a2;
(np porównania) pozostaje
double a3;
double a3;
} ala;
niezdefiniowany
} ala;
«% Kompilator musi mieć możliwość
struct struktura {
struct struktura {
określenia wielkości każdego pola
double a;
double a;
char nn[5];
definiowanej struktury
char nn[5];
costam ct;
costam ct;
«% UWAGA rozmiar struktury nie zawsze
struktura *nast;
struktura *nast;
musi być równy sumie rozmiarów jej pól i
};
};
taki sam na różnych systemach
Zaawansowane techniki programowania
Składnia C++
vð
Struktury
«% DostÄ™p do pól jest możliwy poprzez operator
struct struktura {
struct struktura {
wyłuskania oraz desygnator nazwy pola
double a;
double a;
«% Wskazniki do struktur te same prawa i char nn[5];
char nn[5];
costam ct;
zasady co we wskaznikach ogólnych. Zmienia
costam ct;
struktura *nast;
struktura *nast;
się postać operatora wyłuskania
};
};
«% Dwie struktury nie sÄ… sobie równoważne
nawet jeśli mają identyczną definicję
struktura ms1, *ms2;
struktura ms1, *ms2;
«% Nie ma automatycznego rzutowania typów
ms1.a = 10.1;
ms1.a = 10.1;
«% Nazwy pól nie mogÄ… siÄ™ powtarzać
cout << ms1.a;
cout << ms1.a;
«% MogÄ… istnieć skÅ‚adowe statyczne struktury
ms2 = &ms1;
ms2 = &ms1;
ms2->a = 10.1;
ms2->a = 10.1;
«% Struktura może mieć metody
cout << ms2->a;
cout << ms2->a;
«% Niewielka różnica miÄ™dzy klasÄ… a strukturÄ… w
C++ (struktura to zdegenerowana klasa)
Zaawansowane techniki programowania
Składnia C++
vð
Jawna konwersja typów
«% Odziedziczone po C
double a = (double)10;
«% static_cast rzutowanie typów
double a = (double)10;
double b = double(10);
double b = double(10);
pokrewnych (niepolimorficzne)
«% dynamic_cast rzutowanie typów w
int c = static_cast(a);
int c = static_cast(a);
hierarchii klas (polimorficzne)
«% reinterpret_cast bitowa zmiana
znaczenia adresu (bardzo
niebezpieczne)
«% const_cast usuniÄ™cie kwalifikatorów
const
Zaawansowane techniki programowania
Składnia C++
vð
Przeciążanie nazw funkcji
«% W programie może wystÄ™pować kilka
funkcji o tej samej nazwie
// prawidłowo
// prawidłowo
int funkcja(int _a);
int funkcja(int _a);
«% Kompilator sam dopasuje odpowiedniÄ…
int funkcja(int _a, int _y);
int funkcja(int _a, int _y);
«% Nazwy funkcji muszÄ… siÄ™ różnić o tyle by
int funkcja(double _a);
int funkcja(double _a);
int funkcja(string _a);
było możliwe ich rozróżnienie przez int funkcja(string _a);
kompilator
// nieprawidłowo
// nieprawidłowo
«% Typ wartoÅ›ci zwracanej nie jest
int funkcja(int _a);
int funkcja(int _a);
double funkcja(int _a);
double funkcja(int _a);
rozpatrywany przy przeciążaniu nie
może być wykorzystany do przeciążania.
Zaawansowane techniki programowania
Składnia C++
vð
Kolejność poszukiwania
«% ÅšcisÅ‚a zgodność (bez konwersji lub konwersje trywialne tablica
na wskaznik, stała na zmienną, nazwa funkcji na funkcję)
«% Zgodność z zastosowaniem promowania typów caÅ‚oÅ›ciowych
(bool na int, char na int i odpowiedniki bez znaku)
«% Zgodność z zachowaniem standardowych konwersji (caÅ‚kowite na
zmiennoprzecinkowe i vice versa, rzutowania klas, rzutowanie na
void*)
«% Zgodność z zachowaniem definiowanych konwersji (dla klas)
«% Zgodność z wielokropkiem w deklaracji funkcji.
«% JeÅ›li znaleziono wiÄ™cej niż jednÄ… pasujÄ…cÄ… funkcjÄ™ na tym samym
poziomie będzie błąd kompilacji.
«% Uwaga na przekazywanie statycznych tablic wielowymiarowych!
Zaawansowane techniki programowania
Składnia C++
vð
Kolejność poszukiwania
void drukuj(int _x);
void drukuj(int _x);
void drukuj(const char* _x);
void drukuj(const char* _x);
void drukuj(double _x);
void drukuj(double _x);
void drukuj(long _x);
void drukuj(long _x);
void drukuj(char _x);
void drukuj(char _x);
void h(char _c, int i, short s, float f)
void h(char _c, int i, short s, float f)
{{
// scisla zdodnosc
// scisla zdodnosc
drukuj(c);
drukuj(c);
drukuj(i);
drukuj(i);
// trywialna konwersja
// trywialna konwersja
drukuj('c');
drukuj('c');
drukuj(49);
drukuj(49);
drukuj(0);
drukuj(0);
drukuj("A");
drukuj("A");
// promocja w zakresie calosciowych
// promocja w zakresie calosciowych
drukuj(s); // wywola drukuj(int)
drukuj(s); // wywola drukuj(int)
// promocja w zakresie konw. standardowych
// promocja w zakresie konw. standardowych
drukuj(f); // wywola drukuj(double)
drukuj(f); // wywola drukuj(double)
}
}
Zaawansowane techniki programowania
Składnia C++
vð
Kolejność poszukiwania
void f1(char);
void f1(char);
void f1(long);
void f1(long);
«% RÄ™czne usuwanie niejednoznacznoÅ›ci
void f2(char*);
void f2(char*);
void f2(int*);
void f2(int*);
«% Rozstrzyganie w razie wielu
...
...
argumentów wykorzystany zostanie
int i;
int i;
najprostszy algorytm.
f1(i); // niejednoznaczne
f1(i); // niejednoznaczne
f1(long(i)); // ok
f1(long(i)); // ok
«% PomiÄ™dzy funkcjami z dwoma lub
f2(0); // niejednoznaczne
f2(0); // niejednoznaczne
więcej argumentów, szuka się
f2(static_cast(0));
f2(static_cast(0));
najlepszego dopasowania dla każdego
// ok
// ok
arg. wg wspomnianych reguł wołając
double pow(int x, int y);
double pow(int x, int y);
funkcjÄ™ pasujÄ…cÄ… najlepiej dla jednego i
double pow(double x, double
double pow(double x, double
co najmniej tak samo dla pozostałych.
y);
y);
Jeśli nie istnieje błąd kompilacji.
...
...
pow(2.0, 2);
pow(2.0, 2);
// niejednoznaczne
// niejednoznaczne
Zaawansowane techniki programowania
Składnia C++
vð
Makropolecenia
#define NAZWA reszta wiersza
«% Ważne i przydatne w C #define NAZWA reszta wiersza
#define MAKRO(x,y) argument1: x
#define MAKRO(x,y) argument1: x
«% W C++ - zÅ‚oÅ›liwe, choć czasem argument2: y
argument2: y
niezastÄ…pione
rozw = MAKRO(the knights, say ni)
rozw = MAKRO(the knights, say ni)
«% #define tworzy makro
argument1: the knights argument2: say ni
żð
Problemy
argument1: the knights argument2: say ni
«% Brak sprawdzania skÅ‚adni
// rozsÄ…dne:
// rozsÄ…dne:
#define CASE break; case
#define CASE break; case
«% Nie można debugować
#define FOREVER while(1)
#define FOREVER while(1)
«% Trudniej szukać
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MIN(a,b) (((a)<(b))?(a):(b))
żð
Kiedy stosować:
// nierozsÄ…dne:
// nierozsÄ…dne:
«% StaÅ‚e napisowe #define SQR(a) a*a
#define SQR(a) a*a
«% MIN, MAX, ABS
int y = SQR(x+2); // tzn x+2*x+2 !!!
int y = SQR(x+2); // tzn x+2*x+2 !!!
«% Niektóre szablony kodu
«% Kompilacja warunkowa
Zaawansowane techniki programowania
Składnia C++
vð
Makropolecenia
# ifdef HAVE_ISNAN
# ifdef HAVE_ISNAN
# include
# include
# else
# else
# if !defined(__MINGW32__) && !defined(_MSC_VER) && !defined(__BORLANDC__)
# if !defined(__MINGW32__) && !defined(_MSC_VER) && !defined(__BORLANDC__)
# error "Local 'isnan' implementation only for use with MINGW, Borland and VC++"
# error "Local 'isnan' implementation only for use with MINGW, Borland and VC++"
# endif
# endif
#define LOOP_SUM_FUNC_OBJ(CLASSNAME,FUNCNAME,EXPR,LOOPMAX) \
#define LOOP_SUM_FUNC_OBJ(CLASSNAME,FUNCNAME,EXPR,LOOPMAX) \
double CLASSNAME::FUNCNAME(const CWUTSteamCalculator &c) const{ \
double CLASSNAME::FUNCNAME(const CWUTSteamCalculator &c) const{ \
double s=0; \
double s=0; \
for(int i=0;ifor(int i=0;is+=(EXPR); \
s+=(EXPR); \
} \
} \
return s; \
return s; \
}}
#define EXPR_FUNC_OBJ(CLASSNAME,FUNC,EXPR,TYPE) \
#define EXPR_FUNC_OBJ(CLASSNAME,FUNC,EXPR,TYPE) \
TYPE CLASSNAME::FUNC(const CWUTSteamCalculator &c) const{ \
TYPE CLASSNAME::FUNC(const CWUTSteamCalculator &c) const{ \
TYPE FUNC=(EXPR); \
TYPE FUNC=(EXPR); \
return FUNC; \
return FUNC; \
}}
Zaawansowane techniki programowania
Składnia C++
namespace moja {
namespace moja {
void drukuj(int x);
void drukuj(int x);
vð
void czytaj(int x);
Przestrzenie nazw
void czytaj(int x);
}}
«% Logicznie grupuje
namespace symbole {
namespace symbole {
«% Ukrywa szczegóły implementacji
enum enSymbol { LEWO, PRAWO,
enum enSymbol { LEWO, PRAWO,
«% Wszystkie deklaracje wewnÄ…trz
SRODEK };
SRODEK };
przestrzeni
int doDruku;
int doDruku;
enSymbol jakDruk;
enSymbol jakDruk;
«% Definicje poza przestrzeniÄ… lub
}}
wewnÄ…trz (polecane pierwsze
void moja::drukuj(int x) {
podejście)
void moja::drukuj(int x) {
...
...
«% Możliwe skróty aliasy
}}
«% Możliwe komponowanie i hierarchia
void moja::napisz(int x);//blad
void moja::napisz(int x);//blad
«% Przeszukiwanie przestrzeni nazw we
własnej, nadrzędnych oraz
void moja::czytaj(int x) {
void moja::czytaj(int x) {
symbole::enSymbol jj;
przestrzeniach nazw argumentów!
symbole::enSymbol jj;
// lub:
// lub:
«% Zastosowanie głównie do interfejsów
using symbole::enSymbol;
using symbole::enSymbol;
enSymbol jj;
enSymbol jj;
// lub:
// lub:
using namespace symbole;
using namespace symbole;
enSymbol jj;
enSymbol jj;
}}
Zaawansowane techniki programowania
Programowanie obiektowe
vð
Za poszczególne funkcje oprogramowania
odpowiedzialne sÄ… obiekty
vð
Wyszukujemy je na bazie bytów w dziedzinie
problemu
vð
Przykład:
żð
Napisać program odczytujący z czujników temperaturę i
rysujÄ…cy jej wykres na ekranie.
«% Program
«% Czujnik
«% Temperatura
«% Wykres
" OÅ›
" Seria danych
«% Ekran
«% Zegar ???
Zaawansowane techniki programowania
UML reprezentacja klasy
Zaawansowane techniki programowania
Programowanie obiektowe - klasy
vð
Definiowane przez słowo kluczowe class lub struct
żð
Pola (inne wartości dla różnych instancji)
żð
Metody (takie same dla wszystkich)
żð
Niestandardowe właściwości, zdarzenia.
żð
Ochrona danych:
«% W praktyce oznacza możliwość zdefiniowania obszaru widocznoÅ›ci danej
zmiennej lub funkcji poprzez odpowiednie jej zdefiniowanie. Standard
programowania obiektowego przewiduje występowanie trzech typów ochrony
zmiennych.
«% Pola i metody mogÄ… być publiczne (ang. public), co oznacza, że sÄ… one
dostępne z dowolnego miejsca w programie. Domyślne dla struktur.
«% JeÅ›li chcemy uniemożliwić jakikolwiek dostÄ™p do zmiennej lub metody spoza
implementacji metod wchodzących w jej skład, deklarujemy ją jako prywatną
(ang. private). W C++ jest to zachowanie domyślnie dla klasy.
«% Trzecim typem sÄ… zmienne chronione (ang. protected) - dostÄ™pne podczas
implementacji danego obiektu i wszystkich obiektów pochodnych.
Zaawansowane techniki programowania
Klasa w C++
void CMojObiekt::metoda_prywatna()
void CMojObiekt::metoda_prywatna()
{{
zmienna_publiczna = 1;
zmienna_publiczna = 1;
metoda_publiczna();
metoda_publiczna();
zmienna_prywatna = 1;
zmienna_prywatna = 1;
inna_metoda_prywatna();
inna_metoda_prywatna();
};
};
void CMojObiekt::metoda_publiczna()
void CMojObiekt::metoda_publiczna()
class CMojObiekt
class CMojObiekt
{{
{{
zmienna_publiczna = 1;
zmienna_publiczna = 1;
private:
private:
inna_metoda_publiczna();
inna_metoda_publiczna();
int zmienna_prywatna;
int zmienna_prywatna;
zmienna_prywatna = 1;
zmienna_prywatna = 1;
void metoda_prywatna();
void metoda_prywatna();
metoda_prywatna();
metoda_prywatna();
int inna_metoda_prywatna();
int inna_metoda_prywatna();
};
};
public:
public:
int zmienna_publiczna;
int zmienna_publiczna;
CMojObiekt mo;
CMojObiekt mo;
void metoda_publiczna();
void metoda_publiczna();
int
int
...
...
inna_metoda_publiczna();
inna_metoda_publiczna();
mo.zmienna_publiczna = 1; // prawidłowo
mo.zmienna_publiczna = 1; // prawidłowo
};
};
mo.metoda_publiczna(); // prawidłowo
mo.metoda_publiczna(); // prawidłowo
mo.zmienna_prywatna= 1;
mo.zmienna_prywatna= 1; // zle
// zle
mo.metoda_prywatna(); // zle
mo.metoda_prywatna(); // zle
...
...
Zaawansowane techniki programowania
Klasa w C++
void CMojObiekt::metoda_prywatna()
void CMojObiekt::metoda_prywatna()
{{
zmienna_publiczna = 1;
zmienna_publiczna = 1;
metoda_publiczna();
metoda_publiczna();
zmienna_prywatna = 1;
zmienna_prywatna = 1;
inna_metoda_prywatna();
inna_metoda_prywatna();
};
};
void CMojObiekt::metoda_publiczna()
void CMojObiekt::metoda_publiczna()
class CMojObiekt
class CMojObiekt
{{
{{
zmienna_publiczna = 1;
zmienna_publiczna = 1;
private:
private:
inna_metoda_publiczna();
inna_metoda_publiczna();
int zmienna_prywatna;
int zmienna_prywatna;
zmienna_prywatna = 1;
zmienna_prywatna = 1;
void metoda_prywatna();
void metoda_prywatna();
metoda_prywatna();
metoda_prywatna();
int inna_metoda_prywatna();
int inna_metoda_prywatna();
};
};
public:
public:
int zmienna_publiczna;
int zmienna_publiczna;
CMojObiekt* mo;
CMojObiekt* mo;
void metoda_publiczna();
void metoda_publiczna();
int
int
...
...
inna_metoda_publiczna();
inna_metoda_publiczna();
mo = new CMojObiekt();
mo = new CMojObiekt();
};
};
mo->zmienna_publiczna = 1; // prawidłowo
mo->zmienna_publiczna = 1; // prawidłowo
mo->metoda_publiczna(); // prawidłowo
mo->metoda_publiczna(); // prawidłowo
delete mo;
delete mo;
...
...
Zaawansowane techniki programowania
Konstruktor i destruktor
vð
Konstruktor
«% Konstruktor jest metodÄ…, która nic nie zwraca, i nazywa siÄ™ tak
samo jak klasa. Następnie, podobnie jak w zwykłej funkcji,
można podać listę parametrów.
«% Daje możliwość inicjacji wszystkich pól.
«% Pozwala utworzyć zmienne dynamiczne wchodzÄ…ce w skÅ‚ad
klasy
«% Pozwala dokonać wszystkich innych niezbÄ™dnych w trakcie
tworzenia obiektu działań.
«% Możliwe różne postacie (przeciążanie) np. mogÄ… posÅ‚użyć do
wykonania kopii obiektu przekazanego jako wzorzec.
«% Obiekty zawsze sÄ… tworzone przy wykorzystaniu konstruktora.
Nawet jeśli nie wywoła się go jawnie, w C++ zostanie wywołany
w sposób niejawny. I analogicznie - jeśli nie zostanie w klasie
zdefiniowany żaden konstruktor, kompilator wygeneruje sam
jego domyślną wersję - która nic nie robi. Analogicznie
wygeneruje trywialny płytki konstruktor kopiujący.
Zaawansowane techniki programowania
Konstruktor i destruktor
vð
Destruktor
«% Metoda, która jest wywoÅ‚ywana w trakcie niszczenia obiektu.
Destruktor jest zawsze bezparametrowy i nie zwraca wartości,
zawsze nazywa siÄ™ tak jak nazwa klasy, poprzedzona znakiem
tyldy ~
«% W C++ nie istnieje formalny wymóg definicji konstruktorów czy
destruktorów dla każdego typu obiektu, jednak - dobry styl
wymaga, aby konstruktor zawsze był, choćby w celu przypisania
zmiennym wartości domyślnych.
Zaawansowane techniki programowania
Klasa w C++
class CProstokat
class CProstokat
{{ void f(CProstokat p) { ... }
void f(CProstokat p) { ... }
public:
public:
// konstr. 1 przed uruchomieniem programu
// konstruktor 1 - domyślny
// konstr. 1 przed uruchomieniem programu
// konstruktor 1 - domyślny
CProstokat pr;
CProstokat();
CProstokat pr;
CProstokat();
// konstr. 1 przed uruchomieniem programu
// konstruktor 2 - kopiujÄ…cy
// konstr. 1 przed uruchomieniem programu
// konstruktor 2 - kopiujÄ…cy
CProstokat pr2;
CProstokat(const CProstokat& wzor);
CProstokat pr2;
CProstokat(const CProstokat& wzor);
// destruktor
// destruktor
// konstr. 2
~CProstokat();
// konstr. 2
~CProstokat();
pr2 = pr;
...
pr2 = pr;
...
};
};
// konstr. 1 po dojściu do tej linii
// konstr. 1 po dojściu do tej linii
CProstokat::CProstokat() CProstokat *pr3 = new CProstokat();
CProstokat::CProstokat() CProstokat *pr3 = new CProstokat();
{{ // konstr. 2 po dojściu do tej linii
// konstr. 2 po dojściu do tej linii
CProstokat *pr3 = new CProstokat(pr);
x1 = y1 = 0;
CProstokat *pr3 = new CProstokat(pr);
x1 = y1 = 0;
x2 = 1;
x2 = 1;
// wywołany zostanie destruktor
...
// wywołany zostanie destruktor
...
}} delete pr3
delete pr3
CProstokat::CProstokat(const CProstokat& wzor) // konstr. 2 przed wejściem do f
CProstokat::CProstokat(const CProstokat& wzor) // konstr. 2 przed wejściem do f
{{ f(pr);
f(pr);
// destruktor
x1 = wzor.x1;
// destruktor
x1 = wzor.x1;
y1 = wzor.y1;
y1 = wzor.y1;
// konstr. 2 po przed wejściem do f
...
// konstr. 2 po przed wejściem do f
...
}} f(*pr);
f(*pr);
// destruktor
// destruktor
CProstokat::~CProstokat()
CProstokat::~CProstokat()
{{
}}
Zaawansowane techniki programowania
Klasa w C++
class CMoja
class CMoja
{{
public:
public:
CMoja() {
CMoja() {
tbl = new char[255];
vð
tbl = new char[255];
Uwaga:
};
};
żð
Domyślne wersje konstruktora i
~CMoja() {
~CMoja() {
delete[] tbl;
delete[] tbl;
destruktora są głupie
}}
żð private:
Kopiowanie jest płytkie wskaznik a
private:
char* tbl;
char* tbl;
nie wskazywana wartość
};
};
żð
Przy przekazywaniu jako wartość
void ff(CMoja m) {
void ff(CMoja m) {
zawsze robiona jest kopia.
...
...
}}
int main() {
int main() {
CMoja obiekt;
CMoja obiekt;
ff(obiekt);
ff(obiekt);
CMoja *po = new CMoja();
CMoja *po = new CMoja();
ff(obiekt);
ff(obiekt);
delete po;
delete po;
return 0;
return 0;
}}
Zaawansowane techniki programowania
Klasa w C++
class CMM
class CMM
vð {{
Zastosowania
public:
public:
niestandardowe
CMM() { pole = 0; }
CMM() { pole = 0; }
private:
private:
CMM(const CMM& src) {}
CMM(const CMM& src) {}
int pole;
żð
int pole;
Zabezpieczenie przed
};
};
kopiowaniem
void f(CMM a)
void f(CMM a)
{{
}}
int main(int argc, char *argv[])
int main(int argc, char *argv[])
{{
CMM a;
CMM a;
// CMM b = a;
// CMM b = a;
// f(a);
// f(a);
system("PAUSE");
system("PAUSE");
return EXIT_SUCCESS;
return EXIT_SUCCESS;
}}
Zaawansowane techniki programowania
Klasa w C++
class CMoja
class CMoja
{{
vð
Zastosowania
public:
public:
CMoja() { cnt++; }
CMoja() { cnt++; }
niestandardowe
CMoja(const CMoja& c) { cnt++; }
CMoja(const CMoja& c) { cnt++; }
int ileMoja() { return cnt; }
int ileMoja() { return cnt; }
static int ileMojaStat() { return cnt; }
static int ileMojaStat() { return cnt; }
private:
private:
żð
Zliczanie kopii i referencji
static int cnt;
static int cnt;
pola statyczne. };
};
int CMoja::cnt = 0;
int CMoja::cnt = 0;
int main(int argc, char *argv[])
int main(int argc, char *argv[])
{{
CMoja a, b, c;
CMoja a, b, c;
cout << a.ileMoja() << endl;
cout << a.ileMoja() << endl;
cout << CMoja::ileMojaStat() << endl;
cout << CMoja::ileMojaStat() << endl;
CMoja d = b;
CMoja d = b;
cout << a.ileMoja() << endl;
cout << a.ileMoja() << endl;
CMoja& e = b;
CMoja& e = b;
cout << a.ileMoja() << endl;
cout << a.ileMoja() << endl;
system("PAUSE");
system("PAUSE");
return EXIT_SUCCESS;
return EXIT_SUCCESS;
}}
Zaawansowane techniki programowania
Klasa w C++ - singleton
vð
Singleton klasa która ma
TClipboard *_Clip = NULL;
TClipboard *_Clip = NULL;
tylko i wyłącznie jedną
void Clip() {
void Clip() {
if (_Clip == NULL)
instancjÄ™.
if (_Clip == NULL)
_Clip = new TClipboard();
_Clip = new TClipboard();
żð
Zapewnić to można poprzez
return _Clip;
return _Clip;
odpowiedniÄ… funkcjÄ™ i zmiennÄ…
}}
statycznÄ…
żð
Lub poprzez metodÄ™ statycznÄ… w
int main()
int main()
{{
klasie.
...
żð
RozwiÄ…zanie drugie jest bardziej
...
Clip()->setText("kot ma ale");
Clip()->setText("kot ma ale");
uniwersalne.
...
...
żð
Korzystanie ze zmiennej globalnej to
}}
nie jest dobry pomysł.
Zaawansowane techniki programowania
Klasa w C++ - singleton
vð
Klasa będąca singletonem
TClipboard *_Clip = NULL;
TClipboard *_Clip = NULL;
tworzona w momencie
void Clip() {
void Clip() {
if (_Clip == NULL)
pojawienia siÄ™
if (_Clip == NULL)
_Clip = new TClipboard();
_Clip = new TClipboard();
zapotrzebowania i
return _Clip;
return _Clip;
}}
automatycznie usuwana z
pamięci jak już nikt z niej
int main()
int main()
{{
nie korzysta
...
...
Clip()->setText("kot ma ale");
Clip()->setText("kot ma ale");
...
...
}}
Zaawansowane techniki programowania
Klasa w C++ - Singleton
#include
#include
#include
#include
using namespace std;
using namespace std;
class A {
class A {
public: int main(int argc, char *argv[])
public: int main(int argc, char *argv[])
{{
static A* getInstance();
static A* getInstance();
void dzialanie(); A *moja = A::getInstance();
void dzialanie(); A *moja = A::getInstance();
private:
private:
A(); moja->dzialanie();
A(); moja->dzialanie();
static A* FInstance;
static A* FInstance;
int FCnt; A *inna = A::getInstance();
int FCnt; A *inna = A::getInstance();
};
};
inna->dzialanie();
inna->dzialanie();
void A::dzialanie() {
void A::dzialanie() {
cout << FCnt++ << " dzialam...\n"; system("PAUSE");
cout << FCnt++ << " dzialam...\n"; system("PAUSE");
}}
return EXIT_SUCCESS;
return EXIT_SUCCESS;
}}
A::A() {
A::A() {
FCnt = 0;
FCnt = 0;
cout << "Tworzenie singletonu\n" ;
cout << "Tworzenie singletonu\n" ;
}}
A* A::FInstance = NULL;
A* A::FInstance = NULL;
A* A::getInstance() {
A* A::getInstance() {
return (FInstance ? FInstance : FInstance = new
return (FInstance ? FInstance : FInstance = new
A());
A());
}}
Zaawansowane techniki programowania
Przeciążanie operatorów
class CPunkt {
class CPunkt {
public:
public:
CPunkt(int _x, int _y);
CPunkt(int _x, int _y);
vð
W C++ można przedefiniować
CPunkt operator+ (CPunkt p);
CPunkt operator+ (CPunkt p);
CPunkt operator* (CPunkt p);
CPunkt operator* (CPunkt p);
znaczenie praktycznie
private:
private:
double x, y;
double x, y;
wszystkich operatorów
}}
żð
WyjÄ…tek: operatory :: . .*
CPunkt CPunkt::operator+(CPunkt p)
CPunkt CPunkt::operator+(CPunkt p)
żð
Nie można definiować nowych
{{
return CPunkt(x+p.x, y+p.y);
operatorów
return CPunkt(x+p.x, y+p.y);
}}
żð
NazwÄ… funkcji operatorowej jest
...
...
słowo kluczowe operator, potem
CPunkt a, b;
CPunkt a, b;
sam operator.
a + b;
a + b;
a.operator+(b);
a.operator+(b);
żð
Obowiązuje zwykła kolejność
...
...
wiązania operatorów
Zaawansowane techniki programowania
Przeciążanie operatorów
class CPunkt {
class CPunkt {
public:
public:
CPunkt(int _x);
CPunkt(int _x);
vð
CPunkt(int _x, int _y);
Operatory
CPunkt(int _x, int _y);
CPunkt operator+ (int p);
CPunkt operator+ (int p);
żð
Dwuargumentowe mogą być
private:
private:
double x, y;
double x, y;
zdefiniowane przy pomocy
}}
niestatycznej metody klasy albo
funkcji dwuargumentowej nie operator+(CPunkt p1, CPunkt p2){
operator+(CPunkt p1, CPunkt p2){
..
..
będącej jej częścią.
}}
żð
Jednoargumentowe niestatyczna
operator+(CPunkt p1, double p2){
operator+(CPunkt p1, double p2){
metoda klasy lub funkcja
..
..
jednoargumentowa
}}
CPunkt p;
CPunkt p;
p+1; // operator z klasy
p+1; // operator z klasy
p+1.0;// drugi spoza klasy
p+1.0;// drugi spoza klasy
p+p; // pierwszy spoza klasy
p+p; // pierwszy spoza klasy
1+p; // CPunkt(1) + p
1+p; // CPunkt(1) + p
Zaawansowane techniki programowania
Przeciążanie operatorów
vð
Operatory
żð
Operator=, operator[], operator-> - ich pierwsze argumenty
muszą być lwartościami
żð
Operatory nie sÄ… generowane na bazie innych,
równoważnych.
«% JeÅ›li a jest int, to ++a oznacza a+=1 oznacza a=a+1;
«% JeÅ›li C jest klasÄ… i ma zdefiniowany jedynie operator+, to dla
zmiennej c typu C ++c nie oznacza c.operator+(1)!
«% Operator =(przypisanie), &(pobranie adresu) i ,(przecinek) sÄ…
generowane automatycznie. Pozostałe nie.
Zaawansowane techniki programowania
UML Diagramy klas
Diagram klas przedstawia ogólną panoramę systemu, pokazując klasy i ich wzajemne relacje.
Diagramy klas sÄ… statyczne - pokazujÄ…, co wchodzi w interakcje, a nie co siÄ™ dzieje podczas
tych interakcji. Zamówienie z katalogu. Centralna klasa to Zamówienie. Z tą klasą związany jest
Klient, który dokonuje zakupu, oraz Płatność. Są trzy rodzaje Płatności: Gotówka, Czek lub
Kredyt. Zamówienie zawiera SzczegółyZam (pozycje transakcji), każdy z powiązaną Pozycją.
Zaawansowane techniki programowania
Relacje pomiędzy obiektami
vð
Cztery zasadnicze rodzaje powiązań:
żð
Skojarzenie obiekt typu A wykorzystuje obiekt typu B i / lub B
wykorzystuje A w celu wykonania swoich zadań. A i B są tworzone
i pamiętane zupełnie niezależnie
żð
Agregacja obiekt typu A zawiera w sobie obiekt typu B, ale oba
są tworzone niezależnie od siebie
żð
Kompozycja obiekt typu A zawiera w sobie obiekt typu B i jest
jego Panem i władcą A tworzy i niszczy B
żð
Uogólnienie obiekt typu B dziedziczy po obiekcie typu A a jest
klasą nadrzędną, B pochodną.
Zaawansowane techniki programowania
Relacje pomiędzy obiektami
class A {
class A {
public:
vð public:
Skojarzenie:
...
...
«% Stosowane w przypadku
void rob_cos(B* dawca);
void rob_cos(B* dawca);
...
...
luznego powiązania obiektów
private:
private:
ze sobÄ…
...
...
«% Zazwyczaj w ten sposób Å‚Ä…czy
};
};
się obiekty spełniające
class B {
class B {
okazjonalnie względem siebie
public:
public:
różne funkcje usługowe.
...
...
void rob_cos(A* dawca);
void rob_cos(A* dawca);
«% Główna wada konieczność
...
...
ręcznego zarządzania czasem
private:
private:
życia obiektów
...
...
};
};
int main() {
int main() {
A obA;
A obA;
B obB;
B obB;
...
...
obA.rob_cos(&obB);
obA.rob_cos(&obB);
...
...
}}
Zaawansowane techniki programowania
Relacje pomiędzy obiektami
class A {
class A {
public:
public:
...
...
vð
Agregacja:
void setB(B *_s);
void setB(B *_s);
«% Silniejsze powiÄ…zanie jeden
void rob_cos();
void rob_cos();
...
...
wchodzi w skład drugiego.
private:
private:
«% Stosowane gdy jeden czÄ™sto
B *czesc
B *czesc
korzysta z drugiego, bÄ…dz };
};
stanowi jego część wymienną
class B {
class B {
«% CiÄ…gle zarzÄ…dzamy czasem
public:
public:
...
życia obiektu ręcznie.
...
private:
private:
...
...
};
};
int main() {
int main() {
A obA;
A obA;
B obB;
B obB;
A.setB(&B);
A.setB(&B);
...
...
obA.rob_cos();
obA.rob_cos();
...
...
}}
Zaawansowane techniki programowania
Relacje pomiędzy obiektami
class A {
class A {
public:
public:
...
...
vð
Kompozycja:
void rob_cos();
void rob_cos();
...
«% Najsilniejsze powiÄ…zanie
...
private:
private:
między dwoma obiektami
B czesc
B czesc
«% Stosowane w momencie gdy B
};
};
jest nieodłączną cechą tylko
class B {
class B {
jednego A, i poza nim sens jego
public:
public:
istnienia jest nieuzasadniony
...
...
private:
«% Najczęściej spotykany zwiÄ…zek private:
...
...
«% A zarzÄ…dza czasem życia B.
};
};
int main() {
int main() {
A obA;
A obA;
...
...
obA.rob_cos();
obA.rob_cos();
...
...
}}
Zaawansowane techniki programowania
UML Diagramy klas
vð
Powiązanie ma dwa końce.
żð
Koniec może mieć nazwę roli, która wyjaśnia naturę
skojarzenia. Na przykład SzczegółZam jest pozycją każdego
Zamówienia.
żð
Strzałka możliwości nawigacji pokazuje kierunek, w którym
można przechodzić lub odpytywać skojarzenie. SzczegółZam
można zapytać o Pozycję, ale nie odwrotnie.
żð
Strzałka informuje też, kto jest "właścicielem" implementacji
skojarzenia; w tym przypadku, SzczegółZam ma Pozycję.
żð
Skojarzenia bez strzałek mają możliwości nawigacji
dwukierunkowe.
Zaawansowane techniki programowania
UML Diagramy klas
Wielokrotność końca skojarzenia to dopuszczalna liczba instancji klasy skojarzonych z jedną
instancją na drugim końcu. Wielokrotności są pojedynczymi liczbami albo zakresami liczb. W
naszym przykładzie może być tylko jeden Klient na każde Zamówienie, ale Klient może mieć
dowolną liczbę Zamówień.
Poniższa tabela opisuje najczęściej używane wielokrotności
Wielokrotności Znaczenie
0..1 Brak lub jedna instancja. n..m oznacza n do m instancji
0..* lub * Bez ograniczenia
1 Dokładnie jedna
1..* Przynajmniej jedna instancja
Zaawansowane techniki programowania
Relacje między obiektami
class CWatroba;
class CWatroba;
class CNerki;
class CNerki;
vð class CKomKrwi;
Przykład: class CKomKrwi;
class CCzlowiek {
«% Agregacje o różnej
class CCzlowiek {
public:
public:
liczebności
CCzlowiek() {
CCzlowiek() {
np = new CNerki;
np = new CNerki;
nl = new CNerki;
nl = new CNerki;
kk_table_size = 2e6;
kk_table_size = 2e6;
kk_table = new CKomKrwi[kk_table_size];
kk_table = new CKomKrwi[kk_table_size];
}}
~CCzlowiek() {
~CCzlowiek() {
if (np) delete np;
if (np) delete np;
if (nl) delete nl;
if (nl) delete nl;
delete[] kk_table;
delete[] kk_table;
}}
void wytnijNerke(bool lewa) {
void wytnijNerke(bool lewa) {
if (lewa) {
if (lewa) {
if (nl) delete nl;
if (nl) delete nl;
nl = NULL;
nl = NULL;
} else {
} else {
if (np) delete np;
if (np) delete np;
np = NULL;
np = NULL;
}}
}}
private:
private:
CWatroba w;
CWatroba w;
CNerki *np, *nl;
CNerki *np, *nl;
CKomKrwi *kk_table;
CKomKrwi *kk_table;
int kk_table_size;
int kk_table_size;
};
};
Zaawansowane techniki programowania
Relacje między obiektami
vð
Czas życia
class C {
class C {
public:
public:
...
...
};
};
class B {
class B {
public:
public:
c : C;
c : C;
...
...
};
};
class A {
class A {
public:
public:
b : B;
b : B;
...
...
};
};
Zaawansowane techniki programowania
Dziedziczenie
żð
Główny mechanizm
wyróżniający programowanie
zorientowane obiektowo od
programowania obiektowego
żð
Opieramy siÄ™ na cechach
wspólnych grupy klas
zarówno jeśli chodzi o pola jak
i metody
żð
Wspólne cechy lądują w klasie
bazowej, cechy szczególne w
klasach pochodnych
Zaawansowane techniki programowania
Dziedziczenie zasady dostępu
vð
Zasady dostępu
żð
Pola prywatne pozostajÄ… prywatne
żð
Pola publiczne nadal sÄ… publiczne
żð
Pola chronione dostępne dla
danej klasy i wszystkich jej dzieci
dla reszty nie.
żð
Obowiązują reguły przykrywania
nazw
żð
Nie obowiÄ…zujÄ… zasady
przeciążania nazw funkcji w
dziedziczeniu!
Zaawansowane techniki programowania
Dziedziczenie zasady dostępu
class CMojObiekt { void CMojNastepca::metoda_prywatna_nastepcy
class CMojObiekt { void CMojNastepca::metoda_prywatna_nastepcy
public: {{
public:
int zmienna_publiczna; // tak mozna
int zmienna_publiczna; // tak mozna
void metoda_publiczna(); zmienna_chroniona = 1;
void metoda_publiczna(); zmienna_chroniona = 1;
protected:
metoda_chroniona();
protected:
metoda_chroniona();
int zmienna_chroniona; // tak natomiast nie da rady
int zmienna_chroniona; // tak natomiast nie da rady
void metoda_chroniona(); zmienna_prywatna = 1;
void metoda_chroniona(); zmienna_prywatna = 1;
private:
metoda_prywatna();
private:
metoda_prywatna();
};
int zmienna_prywatna;
};
int zmienna_prywatna;
void CMojObiekt::metoda_publiczna_nastepcy
void metoda_prywatna();
void CMojObiekt::metoda_publiczna_nastepcy
void metoda_prywatna();
}; {{
};
// tak mozna
// tak mozna
class CMojNastepca : public CMojObiekt { zmienna_chroniona = 1;
class CMojNastepca : public CMojObiekt { zmienna_chroniona = 1;
public:
metoda_chroniona();
public:
metoda_chroniona();
... // tak natomiast nie da rady
... // tak natomiast nie da rady
void metoda_publiczna_nastepcy();
zmienna_prywatna = 1;
void metoda_publiczna_nastepcy();
zmienna_prywatna = 1;
protected:
metoda_prywatna();
protected:
metoda_prywatna();
};
...
};
...
private:
private:
CMojNastepca mn;
void metoda_prywatna_nastepcy;
CMojNastepca mn;
void metoda_prywatna_nastepcy;
}; ...
}; ...
// ponizszy kod jest nieprawidłowy
// ponizszy kod jest nieprawidłowy
mn.zmienna_chroniona = 1;
mn.zmienna_chroniona = 1;
mn.metoda_chroniona();
mn.metoda_chroniona();
Zaawansowane techniki programowania
Dziedziczenie zasady dostępu
class CBaza {
class CBaza {
public:
public:
CBaza() : a(0), b(0), c(0) {};
CBaza() : a(0), b(0), c(0) {};
int a;
int a;
void fa() {cout <<"Baza fa: "<void fa() {cout <<"Baza fa: "<void fb() {cout <<"Baza fb\n";}
void fb() {cout <<"Baza fb\n";}
protected:
protected:
int b;
int b;
private:
private:
int c;
int c;
};
};
class CPoch : public CBaza {
class CPoch : public CBaza {
public:
public:
CPoch() : a(1), b(1), c(1) {};
CPoch() : a(1), b(1), c(1) {};
int a, c;
int a, c;
void fa() {cout <<"Poch fa: "<void fa() {cout <<"Poch fa: "<void fb(int i) {cout <<"Baza fb\n";}
void fb(int i) {cout <<"Baza fb\n";}
void fc() { CBaza::fa(); }
void fc() { CBaza::fa(); }
};
};
int main(int argc, char *argv[])
int main(int argc, char *argv[])
{{
CPoch t;
CPoch t;
t.fa();
t.fa();
// t.fb();
// t.fb();
t.fb(0);
t.fb(0);
t.fc();
t.fc();
system("PAUSE");
system("PAUSE");
return EXIT_SUCCESS;
return EXIT_SUCCESS;
}}
Zaawansowane techniki programowania
Rodzaje dziedziczenia
vð
Publiczne
«% Wszystkie odziedziczone pola i metody majÄ… taki zasiÄ™g jak
zdefiniowano w klasie bazowej. Klasa pochodna i jej pochodne
mają dostęp do części chronionej i publicznej, korzystający z
obiektów pochodnych mają dostęp do części publicznej
vð
Chronione
«% Odziedziczone pola i metody publiczne i chronione stajÄ… siÄ™
chronione w klasie pochodnej i jej pochodnych. Klasa pochodna i
jej pochodne mają dostęp do części chronionej i publicznej,
korzystający z obiektów pochodnych nie mają dostępu do
żadnych pól i metod klasy bazowej
vð
Prywatne
«% Odziedziczone pola i metody publiczne i chronione stajÄ… siÄ™
prywatne w klasie pochodne. Klasa pochodna ma do nich
dostęp, klasy wyprowadzone z pochodnej, oraz korzystający z
obiektów pochodnych nie mają dostępu do żadnych pól i metod
klasy bazowej. Przerwanie przechodzenia uprawnień!
Zaawansowane techniki programowania
Przykład dziedziczenia
Zaawansowane techniki programowania
Przykład dziedziczenia
Zaawansowane techniki programowania
Polimorfizm
class CMalpa {
class CMalpa {
vð
Zróżnicowanie zachowań w
public:
public:
virtual void dajGlos() {
virtual void dajGlos() {
zależności od typu obiektu,
cout << "Hyyyhmyyym\n";
cout << "Hyyyhmyyym\n";
}}
interfejs pozostaje ten sam:
};
};
«% I czÅ‚owiek i maÅ‚pa wydajÄ…
class CCzlowiek : public CMalpa {
class CCzlowiek : public CMalpa {
public:
odgłosy.
public:
virtual void dajGlos() {
virtual void dajGlos() {
«% KtoÅ› kto korzysta z obiektu
cout << "Auuu, boli\n";
cout << "Auuu, boli\n";
}}
klasy człowiek czy też małpa
};
};
nie musi wiedzieć którego typu
int main(int argc, char *argv[])
int main(int argc, char *argv[])
jest dany osobnik by zmusić go
{{
do wydania głosu wystarczy
CMalpa m;
CMalpa m;
CCzlowiek c;
że wie że osobnik wydaje głosy.
CCzlowiek c;
CMalpa *cm;
CMalpa *cm;
«% WywoÅ‚aniem odpowiedniej
m.dajGlos();
m.dajGlos();
wersji funkcji zajmie siÄ™
c.dajGlos();
c.dajGlos();
kompilator.
cm = &m;
cm = &m;
cm->dajGlos();
cm->dajGlos();
cm = &c;
cm = &c;
cm->dajGlos();
cm->dajGlos();
}}
Zaawansowane techniki programowania
Polimorfizm
vð
Funkcje wirtualne
«% Definiowane przy wykorzystaniu sÅ‚owa kluczowego virtual
«% Przy implementacji sÅ‚owa virtual nie wykorzystujemy
«% Przy wywoÅ‚aniu zostanie przeszukana tablica funkcji
wirtualnych przynależąca do danego obiektu i wyszukana
wersja najbliższa w hierarchii dziedziczenia.
«% Nie może zmieniać siÄ™ liczba parametrów (sygnatura) funkcji
wirtualnej.
«% Funkcja zaczyna zachowywać siÄ™ jak wirtualna w momencie
pierwszego pojawienia się słowa virtual
«% Zachowanie wirtualne może (ale nie musi) skoÅ„czyć siÄ™ po
pierwszym wystÄ…pieniu funkcji bez virtual w hierarchii
dziedziczenia
«% Rodzaj dziedziczenia nie wpÅ‚ywa na zachowanie siÄ™ funkcji
wirtualnych (zmienia się jedynie zasięg ich widoczności)
«% Metody statyczne nie mogÄ… być wirtualne
Zaawansowane techniki programowania
Polimorfizm
class A { int main(int argc, char *argv[]) {
class A { int main(int argc, char *argv[]) {
public:
A a; B b; C c;
public:
A a; B b; C c;
virtual void f1() { cout << "A f1\n"; } A* pab, *pac;
A* pab, *pac;
virtual void f1() { cout << "A f1\n"; }
void f2() { cout << "A f2\n"; } B* pbc;
void f2() { cout << "A f2\n"; } B* pbc;
};
pab = &b;
};
pab = &b;
pac = &c;
pac = &c;
class B : public A {
pbc = &c;
class B : public A {
pbc = &c;
public:
cout << "Klasa A:\n";
public:
cout << "Klasa A:\n";
void f1() { cout << "B f1\n"; } a.f1();
void f1() { cout << "B f1\n"; } a.f1();
virtual void f2() { cout << "B f2\n"; } a.f2();
a.f2();
virtual void f2() { cout << "B f2\n"; }
};
cout << "Klasa B:\n";
};
cout << "Klasa B:\n";
b.f1();
b.f1();
class C : public B {
b.f2();
class C : public B {
b.f2();
public:
cout << "Klasa B jako A:\n";
public:
cout << "Klasa B jako A:\n";
void f1() { cout << "C f1\n"; } pab->f1();
void f1() { cout << "C f1\n"; } pab->f1();
virtual void f2() { cout << "C f2\n"; } pab->f2();
pab->f2();
virtual void f2() { cout << "C f2\n"; }
};
cout << "Klasa C:\n";
};
cout << "Klasa C:\n";
c.f1();
c.f1();
c.f2();
c.f2();
cout << "Klasa C jako A:\n";
cout << "Klasa C jako A:\n";
pac->f1();
pac->f1();
pac->f2();
pac->f2();
cout << "Klasa C jako B:\n";
cout << "Klasa C jako B:\n";
pbc->f1();
pbc->f1();
pbc->f2();
pbc->f2();
}}
Zaawansowane techniki programowania
Polimorfizm
class A { int main(int argc, char *argv[]) {
class A { int main(int argc, char *argv[]) {
public:
A a; B b; C c;
public:
A a; B b; C c;
virtual void f1() { cout << "A f1\n"; } A* pab, *pac;
A* pab, *pac;
virtual void f1() { cout << "A f1\n"; }
void f2() { cout << "A f2\n"; } B* pbc;
void f2() { cout << "A f2\n"; } B* pbc;
};
pab = &b;
};
pab = &b;
pac = &c;
pac = &c;
class B : public A {
pbc = &c;
class B : public A {
pbc = &c;
public:
cout << "Klasa A:\n";
public:
cout << "Klasa A:\n";
void f1() { cout << "B f1\n"; } a.f1();
void f1() { cout << "B f1\n"; } a.f1();
virtual void f2() { cout << "B f2\n"; } a.f2();
a.f2();
virtual void f2() { cout << "B f2\n"; }
};
cout << "Klasa B:\n";
};
cout << "Klasa B:\n";
b.f1();
b.f1();
class C : public B {
b.f2();
class C : public B {
b.f2();
public:
cout << "Klasa B jako A:\n";
public:
cout << "Klasa B jako A:\n";
void f1() { cout << "C f1\n"; } pab->f1();
void f1() { cout << "C f1\n"; } pab->f1();
virtual void f2() { cout << "C f2\n"; } pab->f2();
pab->f2();
virtual void f2() { cout << "C f2\n"; }
};
cout << "Klasa C:\n";
};
cout << "Klasa C:\n";
c.f1();
c.f1();
c.f2();
c.f2();
cout << "Klasa C jako A:\n";
cout << "Klasa C jako A:\n";
pac->f1();
pac->f1();
pac->f2();
pac->f2();
cout << "Klasa C jako B:\n";
cout << "Klasa C jako B:\n";
pbc->f1();
pbc->f1();
pbc->f2();
pbc->f2();
}}
Zaawansowane techniki programowania
Polimorfizm
class CFigura {
class CFigura {
public:
public:
vð
Wykorzystanie
virtual void rysuj() { }
virtual void rysuj() { }
void przesun(int _x, int _y)
void przesun(int _x, int _y)
{{
X = _x;
«% Funkcje wirtualne mogÄ… być
X = _x;
Y = _y;
Y = _y;
wywoływane w klasach
rysuj();
rysuj();
bazowych zostanie wtedy
};
};
private:
automatycznie wybrana private:
int X;
int X;
odpowiednia wersja
int Y;
int Y;
};
};
«% W ten sposób możemy
wykorzystywać przy tworzeniu
class CKolo :public CFigura {
class CKolo :public CFigura {
kodu zachowanie jeszcze
public:
public:
virtual void rysuj() {
virtual void rysuj() {
niezdefiniowane, i zależne od
// kod rysowania
// kod rysowania
typu obiektu z którym
}}
};
pracujemy.
};
«% Funkcje wirtualne mogÄ… być
również wykorzystane w kodzie
korzystającym z obiektów
danego typu
Zaawansowane techniki programowania
Polimorfizm
class A {
class A {
public:
public:
vð
Wywołanie funkcji bazowej
virtual void f() { cout << "A f1\n"; }
virtual void f() { cout << "A f1\n"; }
};
};
class B : public A {
class B : public A {
«% Jawne wywoÅ‚anie funkcji
public:
public:
bazowej jest możliwe poprzez
virtual void f() {
virtual void f() {
A::f();
A::f();
podanie poprzedzonej
cout << "B f1\n";
cout << "B f1\n";
dwukropkiem nazwy jej klasy.
}}
};
};
«% Nie ma w C++ możliwoÅ›ci
class C : public B {
niejawnego wywołania class C : public B {
public:
public:
odziedziczonej instancji.
virtual void f() {
virtual void f() {
A::f();
A::f();
«% Ogólnie zasiÄ™g widocznoÅ›ci
B::f();
B::f();
poszczególnych pól i metod w
cout << "C f1\n";
cout << "C f1\n";
}}
klasach może być traktowany
};
};
jako zagnieżdżony z punktu
widzenia dziedziczenia:
namespace A {
namespace B {
namespace C {
} } }
Zaawansowane techniki programowania
Polimorfizm
class CFiguraBaza {
class CFiguraBaza {
public:
public:
vð
Funkcje abstrakcyjne, klasy
virtual void rysuj() = 0;
virtual void rysuj() = 0;
};
};
abstrakcyjne, interfejsy
class Cfigura : public CFiguraBaza {
«% Funkcja zadeklarowana w
class Cfigura : public CFiguraBaza {
public:
public:
klasie jako wirtualna, która nie
virtual void rysuj() = 0;
virtual void rysuj() = 0;
ma definicji jest funkcjÄ…
void przesun(int _x, int _y)
void przesun(int _x, int _y)
{{
abstrakcyjnÄ…
X = _x;
X = _x;
«% W C++ oznaczamy ten fakt
Y = _y;
Y = _y;
rysuj();
piszÄ…c =0 po deklaracji funkcji rysuj();
};
};
«% Klasa która ma choć jednÄ…
private:
private:
int X;
funkcjÄ™ abstrakcyjnÄ… jest
int X;
int Y;
int Y;
klasÄ… abstrakcyjnÄ…
};
};
«% Nie można tworzyć obiektów
class CKolo :public CFigura {
class CKolo :public CFigura {
typu klas abstrakcyjnych
public:
public:
virtual void rysuj() {
virtual void rysuj() {
«% Klasa która ma wszystkie
// kod rysowania
// kod rysowania
metody abstrakcyjne i nie
}}
posiada pól jest interfejsem.
};
};
Zaawansowane techniki programowania
Polimorfizm
class CPunkt {
class CPunkt {
public:
public:
vð
Konstruktory oraz destruktory
CPunkt(int _x, int y);
CPunkt(int _x, int y);
private:
private:
klas pochodnych
int X, Y;
int X, Y;
};
};
«% Można pominąć konstruktory i
destruktory w klasach pochodnych class CPunktX : public CPunkt {
class CPunktX : public CPunkt {
public:
public:
«% JeÅ›li sÄ… definiowane uwaga na
CPunktX() : CPunkt(-1, -1) {}
CPunktX() : CPunkt(-1, -1) {}
CPunktX(int _x, int _y)
CPunktX(int _x, int _y)
zgodność!
: CPunkt(_x, _y) {}
: CPunkt(_x, _y) {}
«% Zarówno konstruktory jak i private:
private:
...
...
destruktory klas bazowych i
};
};
pochodnych są wywoływane w
class CPunktY : public CPunktX
class CPunktY : public CPunktX
ścisłej kolejności, podobnej jak w
{{
przypadku kompozycji
public:
public:
...
...
«% Konstruktor klasy bazowej jest
};
};
class CPunktZ : public CPunkt
zawsze wywoływany przed class CPunktZ : public CPunkt
{{
wywołaniem konstruktora klasy
public:
public:
...
pochodnej
...
};
};
«% Rzeczywista kolejność: alokowana
...
...
CPunktY p1;
CPunktY p1;
pamięć na bazowy, konstruktor
CPunktZ p2; // zle
CPunktZ p2; // zle
bazowy, alokowana pamięć na
pochodny, konstruktor pochodny
Zaawansowane techniki programowania
Polimorfizm
class A {
class A {
vð
Konstruktory oraz destruktory
public:
public:
~A() { cout << "A zniszczono\n"; }
~A() { cout << "A zniszczono\n"; }
klas pochodnych
};
};
class B : public A {
class B : public A {
public:
public:
«% Konstruktor może być wirtualny
~B() { cout << "B zniszczono\n"; }
~B() { cout << "B zniszczono\n"; }
ale to nie ma sensu ... };
};
«% Destruktor powinien być
int main(int argc, char *argv[])
int main(int argc, char *argv[])
{{
wirtualny! Inaczej istnieje
B *b = new B();
B *b = new B();
niebezpieczeństwo wycieków
delete b;
delete b;
A *a = new B();
pamięci.
A *a = new B();
delete a;
delete a;
«% Destruktor powinien być
system("PAUSE");
system("PAUSE");
return EXIT_SUCCESS;
return EXIT_SUCCESS;
deklarowany w klasie bazowej!
}}
Zaawansowane techniki programowania
Kopiowanie i klonowanie
class A {
class A {
public:
public:
vð
Jak kopiować i klonować
A() {};
A() {};
A(const A& _s) { };
A(const A& _s) { };
obiekty pochodne ?
virtual void f() {
virtual void f() {
cout<<"A nadaje\n";
cout<<"A nadaje\n";
}}
};
};
«% Na zdrowy rozum tak jak po
prawo: class B : public A {
class B : public A {
public:
public:
«% To nie dziaÅ‚a klasa bazowa nie
B() {};
B() {};
B(const B& _s) : A(_s) { };
B(const B& _s) : A(_s) { };
wie nic o klasie pochodnej
virtual void f() {
virtual void f() {
«% Jawne wywoÅ‚anie konstruktora też cout<<"B nadaje\n";
cout<<"B nadaje\n";
}}
siÄ™ nie uda.
};
};
«% Częściowo wyjÅ›ciem jest
int main(int argc, char *argv[])
int main(int argc, char *argv[])
rzutowanie typów. Ale musimy
{{
B *b = new B;
B *b = new B;
znać typ obiektu pochodnego
A *a1 = b;
A *a1 = b;
przed skopiowaniem
A *a2 = new A(*a1);
A *a2 = new A(*a1);
//A *a3 = new B(*a1);
//A *a3 = new B(*a1);
«% Inne wyjÅ›cie para copy, clone.
a1->f();
a1->f();
a2->f();
a2->f();
}}
Zaawansowane techniki programowania
Kopiowanie i klonowanie
class A {
class A {
public:
public:
A() {FMyNum = FCnt++; };
A() {FMyNum = FCnt++; };
A(const A& _s) {FMyNum = FCnt++; };
A(const A& _s) {FMyNum = FCnt++; };
virtual void f() { cout<<"A " << FMyNum << " nadaje\n"; }
virtual void f() { cout<<"A " << FMyNum << " nadaje\n"; }
virtual A* clone() { return new A(*this); };
virtual A* clone() { return new A(*this); };
protected:
protected:
static int FCnt;
static int FCnt;
int FMyNum;
int FMyNum;
};
};
int A::FCnt = 0;
int A::FCnt = 0;
class B : public A {
class B : public A {
public:
public:
B() {};
B() {};
B(const B& _s) : A(_s) { };
B(const B& _s) : A(_s) { };
virtual void f() { cout<<"B " << FMyNum << " nadaje\n"; }
virtual void f() { cout<<"B " << FMyNum << " nadaje\n"; }
virtual A* clone() { return new B(*this); };
virtual A* clone() { return new B(*this); };
};
};
int main(int argc, char *argv[])
int main(int argc, char *argv[])
{{
B *b = new B;
B *b = new B;
A *a1 = b;
A *a1 = b;
A *a2 = new A(*a1);
A *a2 = new A(*a1);
A *a4 = a1->clone();
A *a4 = a1->clone();
a1->f();
a1->f();
a2->f();
a2->f();
a4->f();
a4->f();
}}
Zaawansowane techniki programowania
Kopiowanie i klonowanie
class A {
class A {
public:
public:
vð
Fabryki obiektów
A() {};
A() {};
A(const A& _s) { };
A(const A& _s) { };
virtual void f() {
virtual void f() {
cout<<"A nadaje\n";
cout<<"A nadaje\n";
«% Jak tworzyć nowe obiekty typu
}}
bazowego bez informacji o typie };
};
pochodnym?
class B : public A {
class B : public A {
public:
public:
«% Fabryka obiektów klasa
B() {};
B() {};
B(const B& _s) : A(_s) { };
B(const B& _s) : A(_s) { };
virtual void f() {
virtual void f() {
cout<<"B nadaje\n";
cout<<"B nadaje\n";
}}
};
};
int main(int argc, char *argv[])
int main(int argc, char *argv[])
{{
B *b = new B;
B *b = new B;
A *a1 = b;
A *a1 = b;
A *a2 = new A(*a1);
A *a2 = new A(*a1);
//A *a3 = new B(*a1);
//A *a3 = new B(*a1);
a1->f();
a1->f();
a2->f();
a2->f();
}}
Zaawansowane techniki programowania
Kopiowanie i klonowanie
class ICTransformObject
class ICTransformObject
{{
public:
public:
virtual ~ICTransformObject() {}
virtual ~ICTransformObject() {}
virtual void init() = 0;
virtual void init() = 0;
virtual void release() = 0;
virtual void release() = 0;
virtual void beforeCalc() = 0;
virtual void beforeCalc() = 0;
virtual void calculate() = 0;
virtual void calculate() = 0;
virtual void afterCalc() = 0;
virtual void afterCalc() = 0;
virtual ICWUTProperties* getProps() = 0;
virtual ICWUTProperties* getProps() = 0;
...
...
};
};
class ICTransformObjectFactory
class ICTransformObjectFactory
{{
public:
public:
virtual ~ICTransformObjectFactory() {};
virtual ~ICTransformObjectFactory() {};
virtual ICTransformObject* create() = 0;
virtual ICTransformObject* create() = 0;
virtual bool isValid(const ICTransformObject* _ptr) const = 0;
virtual bool isValid(const ICTransformObject* _ptr) const = 0;
virtual void destroy(ICTransformObject* _ptr) = 0;
virtual void destroy(ICTransformObject* _ptr) = 0;
virtual const char* getTypeName() const = 0;
virtual const char* getTypeName() const = 0;
...
...
};
};
Wyszukiwarka
Podobne podstrony:
MS Access 2000 PL Zaawansowane techniki programowania
MS Access 97 PL Zaawansowane techniki programowania
Zaawansowane techniki programowania 03 Szablony
Zaawansowane techniki programowania 04 Gniazda
Debugowanie NET Zaawansowane techniki diagnostyczne?bnet
Technik informatyk12[01] Z3 u
Ćwiczenie nr 14 – Zaawansowane możliwości programu
Technik informatyk12[01] Z4 n
technik informatyk12[01] O1 u
Inkscape Zaawansowane funkcje programu
08 01 skladniki oprogramowania sieci klient karta protokol usluga
więcej podobnych podstron