Wykład 2

Transkrypt

Wykład 2
Programowanie obiektowe w C++
Wykład 2
dr Lidia Stępień
Akademia im. Jana Długosza
w Częstochowie
L. Stępień (AJD)
POwCPP
1 / 17
Referencje jako parametry funkcji
Najczęstszym zastosowaniem referencji jest wykorzystanie jej jako
parametrów funkcji - przekazanie przez referencję.
W tej roli nazwa zmiennej referencyjnej widoczna w funkcji jest
aliasem zmiennej programu wywołującego.
Wywołanie funkcji oznacza zainicjalizowanie parametrów funkcji
wartościami argumentów wywołania funkcji.
Przyspieszenie wykonywania programu dzięki przekazaniu referencji
zamiast całego obiektu danych (szczególnie ważne jest to w przypadku
dużych obiektów danych, jak struktury i egzemplarze klas.
L. Stępień (AJD)
POwCPP
2 / 17
// Przykład 1
#include<iostream>
using namespace std;
// void Zamien(int, int);
void Zamien(int*, int*);
void Zamien(int&, int&);
// #1
// #2
// #3
int main(){
int a = 2, b = 5;
cout << a << ", " << b << endl;
Zamien(a,b); cout << a << ", " << b << endl;
Zamien(&a,&b); cout << a << ", " << b << endl;
}
void Zamien(int x, int y){
int z = x; x = y; y = z;
}
void Zamien(int* x, int* y){
int z = *x; *x = *y; *y = z;
}
void Zamien(int &x, int &y){
int z = x; x = y; y = z;
}
L. Stępień (AJD)
POwCPP
3 / 17
// Przykład 2
#include<iostream>
using namespace std;
int Szescian(int);
// #1
int rSzescian(int&); // #2
int main(){
int a = 2;
cout << a << " ^ 3 =
cout << a << " ^ 3 =
cout << a << " ^ 3 =
}
" << Szescian(a) << endl;
" << rSzescian(a) << endl;
" << Szescian(a) << endl;
int Szescian(int x){
x *= x * x;
return x;
}
int rSzescian(int rx){
rx *= rx * rx;
return rx;
}
L. Stępień (AJD)
POwCPP
4 / 17
UWAGI
Jeśli chcemy, aby funkcja nie zmieniała wartości przekazanych jej przez
refernecję, należy skorzystać z referencji stałej.
int rSzescian(const int& rx);
Przy próbie zmiany wartości zmiennej rx, kompilator zgłosi błąd.
Kompilator zgłosi błąd przy próbie wywołania funkcji mającej
parametry referencyjne dla paramertu nie l-wartości.
Jeśli parametr wywołania funkcji nie jest l-wartością, albo nie jest
zgodny co do typu do odpowiedniego stałego parametru
referencyjnego, C++ tworzy zmienną anonimową właściwego typu i
przypisuje jej wartość przekazanego parametru. Od tej chwili parametr
odnosi się do takiej zmiennej anonimowej.
Kiedy tylko jest możliwe, należy używać specyfikatora const.
L. Stępień (AJD)
POwCPP
5 / 17
Powody deklarowania parametrów referencyjnych jako
stałych:
Użycie const chroni przed niezamierzoną zmianą wartości.
Użycie const pozwala funkcji przetwarzać wartości stałe i niestałe pominięcie const spowoduje, że funkcja będzie tylko przetwarzać tylko
dane niebędące stałymi.
Użycie stałej referencji pozwala funkcji generować tymczasowe
zmienne i ich używać.
L. Stępień (AJD)
POwCPP
6 / 17
Zwracanie wartości przez funkcję
Gdy funkcja zwraca zwyczajną wartość (jak przekazywanie parametru
przez wartość) dochodzi do obliczenia wartości wyrażenia instrukcji
return i przekazania obliczonej wartości do miejsca wywołania funkcji.
Koncepcyjnie dochodzi wówczas do skopiowania wartości zwracanej do
tymczasowej lokalizacji, w której jest dostępna dla programu
wywołującego, np.
double wynik = sqrt(16.0);
cout << sqrt(25.0) << endl;
L. Stępień (AJD)
POwCPP
7 / 17
Zwracanie referencji przez funkcję
Funkcja zwracająca referencję jest tak naprawdę aliasem zmiennej,
której referencja dotyczy.
double wynik = sqrt(16.0);
cout << sqrt(25.0) << endl;
int& F(const int &x){
x+=x*x;
return x;
}
int x = 2;
int w = F(x);
W przypadku zwracania przez funkcję referencji, mamy bezpośrednie
kopiowanie zwracanej wartości x do w .
L. Stępień (AJD)
POwCPP
8 / 17
UWAGI
Należy unikać zwracania referencji do zmiennej tymczasowej, która
przestanie istnieć w chwili zakończenia wykonywania funkcji.
(Analogicznie dla wskaźników.)
Najprostszym rozwiązaniem jest zwracanie referencji przekazanej
wcześniej jako parametr funkcji.
Innym rozwiązaniem jest alokacja pamięci operatorem new.
L. Stępień (AJD)
POwCPP
9 / 17
Kiedy używać referencji, kiedy wskaźników, a kiedy
przekazywać przez wartość?
Funkcja korzysta z przekazanych danych (parametrów), ale ich nie
modyfikuje:
Jeśli obiekt jest mały, np. jest to tym wbudowany lub mała struktura,
należy go przekazać przez wartość.
Jeśli obiekt danych jest tablicą - musimy użyć wskaźnika. Wskaźnik
powinien być typu const.
Jeśli obiekt danych jest duży, należy użyć wskaźnika const lub
referencji const, by zwiększyć szybkość działania programu.
Jeśli obiekt danych jest egzemplarzem klasy, należy użyć referencji
const. W C++ to właśnie dla klas stworzono referencję.
L. Stępień (AJD)
POwCPP
10 / 17
Kiedy używać referencji, kiedy wskaźników, a kiedy
przekazywać przez wartość?
Funkcja korzysta z przekazanych danych (parametrów), ale ich nie
modyfikuje:
Jeśli obiekt jest mały, np. jest to tym wbudowany lub mała struktura,
należy go przekazać przez wartość.
Jeśli obiekt danych jest tablicą - musimy użyć wskaźnika. Wskaźnik
powinien być typu const.
Jeśli obiekt danych jest duży, należy użyć wskaźnika const lub
referencji const, by zwiększyć szybkość działania programu.
Jeśli obiekt danych jest egzemplarzem klasy, należy użyć referencji
const. W C++ to właśnie dla klas stworzono referencję.
L. Stępień (AJD)
POwCPP
10 / 17
Kiedy używać referencji, kiedy wskaźników, a kiedy
przekazywać przez wartość?
Funkcja korzysta z przekazanych danych (parametrów), ale ich nie
modyfikuje:
Jeśli obiekt jest mały, np. jest to tym wbudowany lub mała struktura,
należy go przekazać przez wartość.
Jeśli obiekt danych jest tablicą - musimy użyć wskaźnika. Wskaźnik
powinien być typu const.
Jeśli obiekt danych jest duży, należy użyć wskaźnika const lub
referencji const, by zwiększyć szybkość działania programu.
Jeśli obiekt danych jest egzemplarzem klasy, należy użyć referencji
const. W C++ to właśnie dla klas stworzono referencję.
L. Stępień (AJD)
POwCPP
10 / 17
Kiedy używać referencji, kiedy wskaźników, a kiedy
przekazywać przez wartość?
Funkcja korzysta z przekazanych danych (parametrów), ale ich nie
modyfikuje:
Jeśli obiekt jest mały, np. jest to tym wbudowany lub mała struktura,
należy go przekazać przez wartość.
Jeśli obiekt danych jest tablicą - musimy użyć wskaźnika. Wskaźnik
powinien być typu const.
Jeśli obiekt danych jest duży, należy użyć wskaźnika const lub
referencji const, by zwiększyć szybkość działania programu.
Jeśli obiekt danych jest egzemplarzem klasy, należy użyć referencji
const. W C++ to właśnie dla klas stworzono referencję.
L. Stępień (AJD)
POwCPP
10 / 17
Kiedy używać referencji, kiedy wskaźników, a kiedy
przekazywać przez wartość?
Funkcja korzysta z przekazanych danych (parametrów), ale ich nie
modyfikuje:
Jeśli obiekt jest mały, np. jest to tym wbudowany lub mała struktura,
należy go przekazać przez wartość.
Jeśli obiekt danych jest tablicą - musimy użyć wskaźnika. Wskaźnik
powinien być typu const.
Jeśli obiekt danych jest duży, należy użyć wskaźnika const lub
referencji const, by zwiększyć szybkość działania programu.
Jeśli obiekt danych jest egzemplarzem klasy, należy użyć referencji
const. W C++ to właśnie dla klas stworzono referencję.
L. Stępień (AJD)
POwCPP
10 / 17
Kiedy używać referencji, kiedy wskaźników, a kiedy
przekazywać przez wartość?
Funkcja modyfikuje przekazane dane:
Jeśli mamy do czynienia z typem wbudowanym, należy użyć
wskaźnika. Wywołanie takiej funkcji jest jednoznaczne.
Jeśli obiekt danych jest tablicą - musimy użyć wskaźnika.
Jeśli obiekt danych jest strukturą używamy wskaźnika lub referencji.
Jeśli obiekt danych jest egzemplarzem klasy, używamy referencji.
Są to tylko wytyczne, czasami konieczne jest dokonanie innego
wyboru niż wcześniej sugerowane :)
L. Stępień (AJD)
POwCPP
11 / 17
Kiedy używać referencji, kiedy wskaźników, a kiedy
przekazywać przez wartość?
Funkcja modyfikuje przekazane dane:
Jeśli mamy do czynienia z typem wbudowanym, należy użyć
wskaźnika. Wywołanie takiej funkcji jest jednoznaczne.
Jeśli obiekt danych jest tablicą - musimy użyć wskaźnika.
Jeśli obiekt danych jest strukturą używamy wskaźnika lub referencji.
Jeśli obiekt danych jest egzemplarzem klasy, używamy referencji.
Są to tylko wytyczne, czasami konieczne jest dokonanie innego
wyboru niż wcześniej sugerowane :)
L. Stępień (AJD)
POwCPP
11 / 17
Kiedy używać referencji, kiedy wskaźników, a kiedy
przekazywać przez wartość?
Funkcja modyfikuje przekazane dane:
Jeśli mamy do czynienia z typem wbudowanym, należy użyć
wskaźnika. Wywołanie takiej funkcji jest jednoznaczne.
Jeśli obiekt danych jest tablicą - musimy użyć wskaźnika.
Jeśli obiekt danych jest strukturą używamy wskaźnika lub referencji.
Jeśli obiekt danych jest egzemplarzem klasy, używamy referencji.
Są to tylko wytyczne, czasami konieczne jest dokonanie innego
wyboru niż wcześniej sugerowane :)
L. Stępień (AJD)
POwCPP
11 / 17
Kiedy używać referencji, kiedy wskaźników, a kiedy
przekazywać przez wartość?
Funkcja modyfikuje przekazane dane:
Jeśli mamy do czynienia z typem wbudowanym, należy użyć
wskaźnika. Wywołanie takiej funkcji jest jednoznaczne.
Jeśli obiekt danych jest tablicą - musimy użyć wskaźnika.
Jeśli obiekt danych jest strukturą używamy wskaźnika lub referencji.
Jeśli obiekt danych jest egzemplarzem klasy, używamy referencji.
Są to tylko wytyczne, czasami konieczne jest dokonanie innego
wyboru niż wcześniej sugerowane :)
L. Stępień (AJD)
POwCPP
11 / 17
Kiedy używać referencji, kiedy wskaźników, a kiedy
przekazywać przez wartość?
Funkcja modyfikuje przekazane dane:
Jeśli mamy do czynienia z typem wbudowanym, należy użyć
wskaźnika. Wywołanie takiej funkcji jest jednoznaczne.
Jeśli obiekt danych jest tablicą - musimy użyć wskaźnika.
Jeśli obiekt danych jest strukturą używamy wskaźnika lub referencji.
Jeśli obiekt danych jest egzemplarzem klasy, używamy referencji.
Są to tylko wytyczne, czasami konieczne jest dokonanie innego
wyboru niż wcześniej sugerowane :)
L. Stępień (AJD)
POwCPP
11 / 17
Kiedy używać referencji, kiedy wskaźników, a kiedy
przekazywać przez wartość?
Funkcja modyfikuje przekazane dane:
Jeśli mamy do czynienia z typem wbudowanym, należy użyć
wskaźnika. Wywołanie takiej funkcji jest jednoznaczne.
Jeśli obiekt danych jest tablicą - musimy użyć wskaźnika.
Jeśli obiekt danych jest strukturą używamy wskaźnika lub referencji.
Jeśli obiekt danych jest egzemplarzem klasy, używamy referencji.
Są to tylko wytyczne, czasami konieczne jest dokonanie innego
wyboru niż wcześniej sugerowane :)
L. Stępień (AJD)
POwCPP
11 / 17
Klasa biblioteczna string
Napis w stylu języka C++ to obiekt typu string:
string s("witam");
Przechowywany w obiekcie napis jest ciągiem znaków o zmiennej
długości.
Korzystanie z typu string wymaga dołączenia pliku nagłówkowego:
#include <string>
i przestrzeni nazw std.
L. Stępień (AJD)
POwCPP
12 / 17
Inicjalizowanie obiektów klasy string
string s1; // tworzy napis pusty
string s2("witam"); // napis z wartością początkową
string s3="od tego zaczynamy"; // to samo co wyżej
string s4(s3); // można inicjować jeden napis drugim
string s7(10,’\n’); // napis ma 10 znaków nowego wiersza
L. Stępień (AJD)
POwCPP
13 / 17
Operacje na obiektach klasy string
Obliczenie długości napisu - metoda length()lub size():
cout << "Napis ma " << s2.length() << " znaków\n";
cout << "Napis ma " << s2.size() << " znaków\n";
Przypisywanie napisów:
string s1, s2;
s1 = "w klasie string tak można";
s2 = s1;
L. Stępień (AJD)
POwCPP
14 / 17
Operacje na obiektach klasy string
Zachowany jest dostęp do pojedynczych znaków (pozycje napisu są
numerowane od 0 do length()-1):
string s("wsisiz.edu.pl");
int ile = s.length();
for (int i = 0; i < ile; ++i)
if (s[i] == ’.’)
s[i] = ’_’;
Sprawdzenie, czy napis jest pusty:
// za pomocą sprawdzenia długości napisu
if (!s2.size()) ...
lub
// empty() zwraca true, jeśli napis nie ma znaków
if (s2.empty()) ...
L. Stępień (AJD)
POwCPP
15 / 17
Operacje na obiektach klasy string
Łączenie napisów (konkatenacja) jest realizowane za pomocą operatora ’+’:
string s1("Adam "), s2("Kowalski "), s3;
s3=s1+s2; // w s3 jest napis "Adam Kowalski "
Do napisu można dołączać znak:
string s1("Adam"),s2("Kowalski"),s3;
s3=s1+’ ’+s2; // w s3 jest napis "Adam Kowalski"
Napisy można porównywać z napisami:
if (s2 == s3) ... // operator == jest przeciążony
Można używać operatorów: ==, !=, >, <, >= i <=
L. Stępień (AJD)
POwCPP
16 / 17
Operacje na obiektach klasy string
Napisy można wyświetlać tak, jak typy podstawowe (przeciążony operator
’«’):
string s("Adam");
cout << s << endl;
Napisy można wczytywać (przeciążony operator ’»’ oraz funkcja getline()):
string s1, s2;
cin >> s1; // do znaku spacji
getline(cin,s2); // do znaku nowej linii: jest on wczytywany,
// ale nie zachowywany
getline(cin,s2,’\n’); // do znaku nowej linii:
// jest on wczytywany, ale nie zachowywany,
// ogranicznik tekstu można zmienić na inny
L. Stępień (AJD)
POwCPP
17 / 17