Wyklad CPP 2


Obiektowe programowanie w języku C++
Kurs podstawowy
Dr inż. Lucjan Miękina
upel.agh.edu.pl/wimir/login/
Katedra Robotyki i Mechatroniki
March 7, 2013
1/19
Obiektowe programowanie w języku C++
Funkcje operatorowe
Funkcje te pozwalają definiować semantykę (czyli znaczenie) operatora. Język C++
posiada niejawnie zdefiniowane standardowe operatory, poznane wcześniej. Ponieważ
każda funkcja może być przeciążona, można nadawać nowy sens znanym operatorom.
UWAGA: nie można definiować nowych operatorów.
Funkcja operatorowa ma nazwÄ™:
operator#
gdzie # jest jest nazwą jednego z predefiniowanych operatorów.
Operator może być zdefiniowany jako:
funkcja składowa klasy. W tym przypadku lewy (albo jedyny) argument operacji
pochodzi z klasy, a prawy (o ile istnieje) jest dostarczany w postaci argumentu
funkcji operatorowej (tu nazwanego r)
funkcja globalna. Wtedy ma ona tyle parametrów, ilu argumentów wymaga dany
operator.
Przykład operatora dodawania
45 Complex& Complex::operator+(const Complex& r) {
46 Complex c("+", Re + r.Re, Im + r.Im); zrealizowanego dla klasy Com-
47 return c;
plex w postaci funkcji skład-
48 }
owej klasy.
Dla porównania, funkcja operatorowa nie należąca do klasy Complex i realizująca
analogiczną operację ma postać:
Complex& operator+(const Complex& lpar, const Complex& ppar) {
Complex tmp("+", lpar.Re + ppar.Re, lpar.Im + ppar.Im);
return tmp;
}
2/19
Obiektowe programowanie w języku C++
Funkcje operatorowe
Nieco inną postać musi posiadać operator kopiujący dla klasy, ponieważ musi on
zwrócić wskazanie na obiekt, do którego zachodzi kopiowanie wartości z
prawostronnego argumentu operacji kopiowania.
Przykład:
61 Complex& Complex::operator=(const Complex& r) {
62 Re = r.Re;
63 Im = r.Im;
64 return *this;
65 }
Można zauważyć, że:
typ rezultatu jest referencjÄ… do klasy
argumentem instrukcji return jest dereferencja obiektu wskazywanego przez this.
Inną kategorią często spotykanych funkcji operatorowych są operatory porównania
(==, !=, <, <=, >, >=), które mają typ rezultatu ustalony jako bool, np.:
67 bool Complex::operator==(const Complex& r) {
68 if(Re == r.Re && Im == r.Im)
69 return true;
70 return false;
71 }
3/19
Obiektowe programowanie w języku C++
Funkcje operatorowe - przykład wykorzystania
Przykład programu wykorzystującego klasę Complex z działaniami wykonanymi za
pomocÄ… funkcji operatorowych:
1 #include
2 #include "Complex.h" 1 lm@arch> ./a.out
3 2 Create objects:
4 int main() { 3 c1: 0x7fffcf8408d0, (1.0, 1.0) created
5 printf("Create objects:"); 4 c2: 0x7fffcf8408f0, (2.0, 2.0) created
6 Complex c1("c1", 1., 1.); 5 add: 0x7fffcf840910, (0.0, 0.0) created
7 Complex c2("c2", 2., 2.); 6 Operations:
8 Complex add("add", 0., 0.); 7 +: 0x7fffcf840880, (3.0, 3.0) created
9 printf("\nOperations:"); 8 +: 0x7fffcf840880, (3.0, 3.0) deleted
10 add = c1 + c2; 9 add: 0x7fffcf840910, (3.0, 3.0)
11 // add=c1.operator+(c2); 10 De-allocate:
12 add.Info(); 11 add: 0x7fffcf840910, (3.0, 3.0) deleted
13 printf("\nDe-allocate:"); 12 c2: 0x7fffcf8408f0, (2.0, 2.0) deleted
14 return 0; 13 c1: 0x7fffcf8408d0, (1.0, 1.0) deleted
15 }
4/19
Obiektowe programowanie w języku C++
Szablony
Szablony znajdują zastosowanie w przypadkach, gdy trzeba zapisać takie same
operacje w odniesieniu do różnych typów danych.
Dotychczasowe rozwiązanie tego problemu mogło polegać na:
napisaniu takiej funkcji dla jednego wybranego typu danej, a następnie
skopiowaniu kodu i zamianie w odpowiednich miejscach typu danej na potrzebny.
Prowadziło to jednak do powtarzania prawie identycznego kodu, różniącego się
tylko typami danych w deklaracjach,
zastosowaniu odpowiednich dyrektyw preprocesora, co nie jest w pełni
bezpieczne.
Zastosowanie szablonu (template) pozwala ominąć te problemy. Działanie
mechanizmu szablonu polega na parametryzacji funkcji lub klasy przy użyciu typu
danej (typ jest parametrem i może przyjmować różne wartości) lub wartości danej.
Rozróżniamy szablony:
funkcji
klas.
Na podstawie dostarczonych wartości parametrów szablonu, kompilator generuje nowe
funkcje lub klasy; ten proces jest nazywany generowaniem instancji (template
instantiation), a klasa lub funkcja wygenerowana na podstawie szablonu i jego
parametrów nazywa się specjalizacją.
5/19
Obiektowe programowanie w języku C++
Szablony
Przykład szablonu funkcji
Jeśli zachodzi potrzeba znajdowania maksimum dwu wartości to tradycyjnie
należałoby zdefiniować funkcje dla wybranych typów danych:
int Max(int p1, int p2) { float Max(float p1, float p2) {
return p1 > p2 ? p1 : p2; return p1 > p2 ? p1 : p2;
} }
lub użyć makrodefinicji w postaci:
#define Max(A,B) ((A) > (B) ? (A) : (B)) // to samo; z zast. makra
Używając szablonu, wystarczy napisać jedną funkcję szablonową:
template
T Max(T p1, T p2) {
return p1 > p2 ? p1 : p2;
}
Funkcja ta spełnia rolę dwu wyżej podanych, a także dla innych typów (long, double,
...). Symbol T występujący w definicji tej funkcji jest parametrem szablonu i jest
zastępowany przez kompilator w trakcie analizy kodu odpowiednim typem
(docelowym), który jest ustalany na podstawie typów użytych w każdym miejscu
wywołania tej funkcji.
6/19
Obiektowe programowanie w języku C++
Szablony
Przykład szablonu klasy
KlasÄ… szablonowÄ… jest rodzina klas zadeklarowana za pomocÄ… szablonu.
Deklaracja klasy szablonowej:
Przykład użycia klasy szablonowej:
1 #include
2
17 int main() {
3 template
18 Liczba Integer(1);
4 class Liczba {
19 Integer.Info();
5 T P1;
20 Liczba Float(3.14);
6 public:
21 Float.Info();
7 Liczba (T p1) : P1(p1) {
22
8 }
23 return 0;
9 Liczba () { };
24 }
10 void Info() {
Rezultat wykonania:
11 std::cout << "P1="
lm@arch> ./a.out
12 << P1
P1=1
13 << std::endl;
14 }; P1=3.14
15 };
T jest parametrem szablonu i określa typ składowej P1 klasy Liczba i typ argumentu
p1 konstruktora.
Szablon może mieć więcej niż jeden parametr, stosownie do potrzeb.
7/19
Obiektowe programowanie w języku C++
Szablony z wieloma parametrami
Klasa z dwoma parametrami szablonu
Pierwszy parametr definiuje typ (jest to typ elementów tablicy), a drugi pełni funkcję
stałej całkowitej (określa ilość elementów tej tablicy). Dla drugiego parametru
dostarczono wartość domyślną równą 5.
Deklaracja klasy szablonowej:
1 #include
2
Przykład użycia klasy szablonowej:
3 template
4 class Tablica {
23 int main() {
5 T tab[I];
24 Tablica tabl;
6 public:
25 for(int i = 0; i < 256; i++)
7 bool Set(int i, T t);
26 tabl.Set(i,   );
8 void Info() {
27 tabl.Set(0,  A );
9 std::cout << "tab="
28 tabl.Set(1,  B );
10 << tab
29 tabl.Set(2,  C );
11 << std::endl;
30 tabl.Set(3,  \0 );
12 };
31 tabl.Info();
13 };
32 return 0;
14 // zapis wart.  t w i-tym elemencie tablicy
33 }
15 template
Rezultat wykonania:
16 bool Tablica ::Set(int i , T t) {
lm@arch> ./a.out
17 if(i < 0 || i >= I)
18 return false; // blad, zly indeks !!! tab=ABC
19 tab[i] = t;
20 return true;
21 }
8/19
Obiektowe programowanie w języku C++
Strumieniowe operatory << i >>
Dla programu w języku C++ standardowo są dostępne następujące strumienie (jako
obiekty):
cin kontroluje pobieranie bajtów ze standardowego wejścia. Obiekt cin jest
zadeklarowany jako:
extern istream cin;
cout kontroluje wysyłanie bajtów do standardowego wyjścia. Obiekt cout jest
zadeklarowany jako:
extern ostream cout;
cerr kontroluje nie-buforowane wysyłanie bajtów do standardowego wyjścia
błędów. Obiekt cerr jest zadeklarowany jako:
extern ostream cerr;
clog kontroluje buforowane wysyłanie bajtów do standardowego wyjścia
diagnostycznego. Obiekt clog jest zadeklarowany jako:
extern ostream clog;
W większości systemów cin jest standardowo połączony z klawiaturą, a cout, cerr i
clog są standardowo połączone z ekranem konsoli. Połączenia te mogą jednak być
przekierowane.
W celu użycia strumieni oznaczonych w.w. nazwami, należy dołączyć plik nagłówkowy
iostream i ewentualnie zadeklarować użycie przestrzeni nazw std, np.:
#include
using namespace std;
9/19
Obiektowe programowanie w języku C++
Strumieniowe operatory << i >>
We/wy dla danych typu standardowego
Klasa ostream posiada operator « dla obsÅ‚ugi operacji wyjÅ›ciowych dla standardowych
typów danych, a klasa istream operator dla obsługi operacji wejściowych.
class ostream : class istream :
public virtual ios public virtual ios
{ {
// ... // ...
public: public:
ostream& operator<<(const char*); istream& operator>>(char*);
ostream& operator<<(char); istream& operator>>(char&);
ostream& operator<<(int); istream& operator>>(int&);
ostream& operator<<(const void*); istream& operator>>(void*);
// ... // ...
}; };
1 #include
2 int main() {
3 int I; double D;
lm@arch> ./a.out
4 std::cout << "Podaj wartosc I ";
5 std::cin >> I; Podaj wartosc I 2
6 std::cout << "Podaj wartosc D ";
Podaj wartosc D 3.1415
7 std::cin >> D;
I=2
8 std::cout << "I=" << I << std::endl
D=3.1415
9 << "D=" << D;
10 return 0;
11 }
10/19
Obiektowe programowanie w języku C++
Strumieniowe operatory << i >>
Standardowe we/wy dla danych o typach zdefiniowanych przez użytkownika (w
klasach)
Dla realizowania operacji we/wy dla obiektów klas, należy zadeklarować w tych klasach
odpowiednie funkcje operatorowe ( « i ) jako zaprzyjaznione, np. dla klasy Complex:
23 friend std::istream& operator>>(std::istream& is, Complex& c);
24 friend std::ostream& operator<<(std::ostream& os, const Complex& c);
Ponadto należy zdefiniować te funkcje jako globalne, np. w przypadku klasy Complex:
73 std::istream& operator >> (std::istream& is, Complex& c) {
74 std::cout << std::endl << "Enter Re and Im: ";
75 is >> c.Re >> c.Im;
76 return is;
77 }
78 std::ostream& operator << (std::ostream& os, const Complex& c) {
79 os << "Re=" << c.Re << ", Im=" << c.Im;
80 return os;
81 }
Program główny i rezultat działania:
1 #include "Complex.h"
2
lm@arch> ./a.out
3 int main() {
NN: 0x4c102cc0, (0.0, 0.0) created
4 Complex c1; // deklaracja
Enter Re and Im: 1.1 2.2
5 std::cin >> c1; // wprowadzenie
Re=1.1, Im=2.2
6 std::cout << c1; // wyprowadzenie
NN: 0x4c102cc0, (1.0, 2.2) deleted
7 return 0;
8 }
11/19
Obiektowe programowanie w języku C++
Strumieniowe operatory << i >>
Plikowe we/wy dla danych o typach standardowych
Dodatkowo dla programu można otworzyć pewną liczbę strumieni skojarzonych z
plikiem na dysku lub urządzeniem typu znakowego, posługując się w tym celu klasami:
ifstream (wejście z pliku)
ofstream (wyjście do pliku).
Klasy te implementujÄ… strumieniowe operatory « i dla standardowych typów danych,
a więc obsługują zapis i odczyt danych tych typów w plikach lub urządzeniach.
class ofstream : public ... { class ifstream : public ... {
public: public:
ofstream& operator << (const char*); ifstream& operator>> (bool&);
ofstream& operator << (char); ifstream& operator>> (char&);
ofstream& operator << (int); ifstream& operator>> (int&);
ofstream& operator << (const void*); ifstream& operator>> (void*&);
// ... // ...
}; };
12/19
Obiektowe programowanie w języku C++
Strumieniowe operatory << i >>
Przykład realizacji plikowego we/wy dla danych o typach standardowych
1 #include
2 #include
3 using namespace std;
4 int main() {
5 int I; double D;
6 cout << "Podaj wartosc I ";
7 cin >> I;
8 cout << "Podaj wartosc D ";
9 cin >> D;
10 cout << "Wprowadzone: ";
11 cout << "I=" << I << ", D=" << D;
lm@arch> ./a.out
12 // ZAPIS
Podaj wartosc I 22222
13 ofstream os;
Podaj wartosc D 3.1415
14 os.open("Std.dat");
Wprowadzone: I=22222, D=3.1415
15 os << I << " " << D;
Wyzerowane: I=0, D=0
16 os.close();
Wczytane: I=22222, D=3.1415
17 I = 0; D = 0.; // zerowanie
18 cout << endl << " Wyzerowane: ";
19 cout << "I=" << I << ", D=" << D;
20 // ODCZYT
21 ifstream is;
22 is.open("Std.dat");
23 is >> I >> D;
24 is.close();
25 cout << endl << " Wczytane: ";
26 cout << "I=" << I << ", D=" << D;
27 }
13/19
Obiektowe programowanie w języku C++
Strumieniowe operatory << i >>
Plikowe we/wy dla danych o typach zdefiniowanych przez użytkownika (w klasach)
Dla realizowania plikowych operacji we/wy dla obiektów klas, należy zadeklarować w
tych klasach odpowiednie funkcje operatorowe ( « i ) jako zaprzyjaznione, np. dla
klasy Complex:
26 friend std::ifstream& operator >> (std::ifstream& is, Complex& c);
27 friend std::ofstream& operator << (std::ofstream& os, const Complex& c);
Ponadto należy zdefiniować te funkcje jako globalne, np. w przypadku klasy Complex:
83 std::ifstream& operator >> (std::ifstream& is, Complex& c) {
84 is >> c.Re >> c.Im;
85 return is;
86 }
87 std::ofstream& operator << (std::ofstream& os, const Complex& c) {
88 os << c.Re << " " << c.Im;
89 return os;
90 }
Zapis w pliku Complex.dat: Odczyt z pliku Complex.dat:
1 #include "Complex.h" 1 #include "Complex.h"
2 using namespace std; 2 using namespace std;
3 int main() { 3 int main() {
4 Complex c("c", 1.1, 1.1); 4 Complex c;
5 ofstream os("Complex.dat"); 5 ifstream is("Complex.dat");
6 os << c; 6 is >> c;
7 os.close(); 7 is.close();
8 return 0; 8 return 0;
9 } 9 }
14/19
Obiektowe programowanie w języku C++
Zaprzyjaznienia
Zaprzyjaznienie jest deklaracją, która nadaje wybranej funkcji zewnętrznej lub innej
klasie takie same przywileje dostępu do składników pewnej klasy, jakie mają jej własne
metody.
Przykład:
class ExtClass; // deklaracja zapowiadajaca klasy
class C {
int Priv; // pole prywatne
friend class ExtClass; // inna klasa zaprzyjazniona z klasa C
friend int ExtFun(void); // zewn. funkcja zaprzyjazniona z klasa C
};
Mechanizm ten definiuje dodatkowy poziom udostępniania składników klasy wybranym
funkcjom lub klasom, stąd należy go używać z ostrożnością.
Deklaracja funkcji lub klasy zaprzyjaznionej może być umieszczona w sekcji publicznej
lub prywatnej, bez zmiany znaczenia.
Podobnie jak metoda klasy, funkcja zaprzyjazniona jest zadeklarowana wewnÄ…trz
deklaracji klasy i dlatego staje się elementem zewnętrznego interfejsu klasy.
W przypadku gdy wszystkie metody danej klasy są zaprzyjaznione z inną klasą, można
zdefiniować zaprzyjaznienie dla całej klasy; w przykładzie powyżej klasa ExtClass jest
zaprzyjazniona z klasÄ… C.
15/19
Obiektowe programowanie w języku C++
Zaprzyjaznienia
Przykład funkcji zaprzyjaznionej z klasą
Funkcja Info, będąca składową klasy Rysunek jest zaprzyjazniona z klasą Punkt i
dzięki temu może mieć dostęp do jej prywatnych pól X i Y :
1 #include
2 using namespace std;
20 int main() {
3
21 Punkt pt;
4 class Punkt;
22 Rysunek rys;
5 class Rysunek {
23 rys.Info(pt);
6 public:
24 }
7 void Info(Punkt& p);
25
8 };
9 class Punkt {
Rezultat działania:
10 int X, Y;
X = 1
11 friend void Rysunek::Info(Punkt& pt);
Y = 2
12 public:
13 Punkt() : X(1), Y(2) { }
UWAGA: nie tylko funkcje
14 };
składowe klasy mogą być za-
15 void Rysunek::Info(Punkt& p) {
przyjaznione z innymi klasami -
16 cout << "X = " << p.X << endl;
także funkcje globalne.
17 cout << "Y = " << p.Y << endl;
18 }
16/19
Obiektowe programowanie w języku C++
Zaprzyjaznienia
Przykład klasy zaprzyjaznionej z inną klasą
Klasa Rysunek jest zaprzyjazniona z klasą Punkt i dzięki temu każda z jej metod może
mieć dostęp do prywatnych składników klasy Punkt, w tym przykładzie pól X i Y :
1 #include
2 using namespace std;
3
4 class Punkt;
5 class Rysunek {
20 int main() {
6 public:
21 Punkt pt;
7 void Info(Punkt& p);
22 Rysunek rys;
8 };
23 rys.Info(pt);
9 class Punkt {
24 }
10 int X, Y;
25
11 friend class Rysunek;
Rezultat działania:
12 public:
X = 1
13 Punkt() : X(1), Y(2) { }
Y = 2
14 };
15 void Rysunek::Info(Punkt& p) {
16 cout << "X = " << p.X << endl;
17 cout << "Y = " << p.Y << endl;
18 }
17/19
Obiektowe programowanie w języku C++
Statyczne składniki klasy
Klasa jest typem danych, a nie obiektem. Każdy obiekt danej klasy standardowo
posiada swoją kopię pól.
Jednak w pewnych zastosowaniach należy się posłużyć innym modelem, w którym
wybrane pola są wspólne dla wszystkich obiektów danej klasy. Należy je wtedy
zadeklarować wewnątrz klasy z użyciem modyfikatora static:
Plik nagłówkowy:
1 class Klasa1 {
2 // deklaracja pola statycznego
3 static char* ClassName;
1 #include "Klasa1.h"
4 public:
2
5 void Info();
3 int main() {
6 };
4 Klasa1 k1;
5 k1.Info();
Plik zródłowy:
6
1 #include
7 return 0;
2 #include "Klasa1.h"
8 }
3
4 // definicja pola statycznego
Rezultat działania:
5 char* Klasa1::ClassName = "Klasa1";
lm@arch> ./a.out
6
ClassName=Klasa1
7 void Klasa1::Info() {
8 std::cout << "\nClassName="
9 << ClassName;
10 }
18/19


Wyszukiwarka

Podobne podstrony:
Wyklad CPP 6
Wyklad CPP 1
Wyklad CPP 7
Wyklad CPP 3
Wyklad CPP 5
CPP WYKLAD 1
CPP WYKLAD 7
CPP WYKLAD 6
CPP WYKLADY ANALIZA 2
CPP WYKLAD 1 2
CPP WYKLAD 3
CPP WYKLAD 4 5
CPP WYKLADY ANALIZA 1
Sieci komputerowe wyklady dr Furtak
Wykład 05 Opadanie i fluidyzacja

więcej podobnych podstron