Programowanie obiektowe
Lab. 2. Obiektowe wejście/wyjście w C++
(c) Krzysztof Urbański 2014, wszelkie prawa zastrzeżone. Materiały te są chronione prawem autorskim. Żaden fragment
publikacji nie może być powielany lub rozpowszechniany w żadnej formie i w żaden sposób bez uprzedniego zezwolenia.
Wyrażam zgodę na użycie tych materiałów w trakcie realizacji kursów dydaktycznych na Wydziale Elektroniki
Mikrosystemów i Fotoniki Politechniki Wrocławskiej w semestrze letnim 2013/2014 r.
Zagadnienia do opanowania:
" Celowość użycia hermetyzacji (prywatyzacja lub ochrona pól i metod klasy).
" SÅ‚owo kluczowe this.
" Przeciążanie operatorów.
" Zaprzyjaznianie operatora z klasą (podejście 1.).
Funkcje z rodziny printf(& ) nie są zbyt bezpieczne w użyciu. Drobna i trudna do wykrycia
literówka może powodować błędne wyświetlanie wyników (zwłaszcza wtedy, gdy pomyłka polega
na użyciu %d zamiast %g, %f lub na odwrót). Poważniejsze w skutkach jest użycie zbyt dużej liczby
elementów % w ciągu formatujących, co przy niedoborze pozostałych argumentów funkcji printf
spowoduje najczęściej szybkie uśmiercenie aplikacji przez system operacyjny w wyniku błędu
ochrony pamięci.
Obiekt cout
Jeśli jest to możliwe, warto zamiast printf() nauczyć się używać nowszego i bezpieczniejszego
sposobu użycia standardowego wejścia/wyjścia, a są nim obiekty cout oraz cin. Niekoniecznie
jednak należy za wszelką cenę rezygnować z printf(& ) każde z tych rozwiązań mają swoje wady i
zalety, poznawszy oba, będziesz mógł świadomie wybrać optymalne z nich.
Zdecydowanie nie polecam używania w jednym programie obu tych mechanizmów łącznie,
może to doprowadzić do zaskakujących rezultatów wynikających z wewnętrznego buforowania
danych przeznaczonych do wyświetlenia w konsoli, zwłaszcza w programie wielowątkowym
(wrócimy do tego tematu w niedalekiej przyszłości).
#include
void main()
{
std::cout << "Hello, world!" << std::endl;
}
Powyższy kod to najprostszy przykład użycia obiektu cout, który jest odpowiednikiem
printf(& ) z stdout. Dla wygody i lepszej czytelności kodu warto domyślnie włączyć przestrzeń nazw
(ang. namespace) o identyfikatorze std. Pozwoli to pomijać przedrostek std::, a kod uprości się do
następującej postaci:
1
Programowanie obiektowe; © Krzysztof UrbaÅ„ski 2014
#include
using namespace std;
void main()
{
cout << "Hello, world!" << endl;
}
Symbol endl oznacza znak końca wiersza, do tej pory używaliśmy znaku \n , rzadziej
dwuznakowej kombinacji \r\n. Użycie endl nie jest konieczne, można pozostać przy magicznym
znaku \n , ale zastąpienie go endl stanowi dobry zwyczaj polepszający przenośność kodu między
różnymi systemami operacyjnymi, które w różny sposób kodują znaki końca wierszy w plikach
tekstowych.
Moglibyśmy zatem posłużyć się także zapisem: cout << "Hello, world!\n";
Operator << w języku C oznaczał przesunięcie bitowe pewnej liczby w lewo o zadaną liczbę
bitów, np. printf("%d %d %d %d %d %d", 1<<0, 1<<1, 1<<2, 1<<3, 1<<4, 1<<5);
Wyświetlone zostaną wyniki: 1 2 4 8 16 32, czyli kolejne potęgi liczby 2.
Skąd takie wyniki? Zastanów się, jak wygląda dwójkowa reprezentacja liczby całkowitej 1 w
systemie dwójkowym, oraz co się stanie, gdy ta jedynka zacznie wędrować w lewo.
Zadanie do samodzielnej realizacji (w domu)
1. Sprawdz, jak działają operatory >> oraz << dla zmiennych oraz liczb różnych typów. Użyj
zmiennych typu int, char, unsigned int, unsigned char, double. Posłuż się wartościami
początkowymi -1, +1, 2, 4, 255, MAX_INT. W tym zadaniu NIE chodzi o to, aby posługiwać
się cout << x; czy cin >> y;. Celem zadania jest użycie operatorów << oraz >> w
odniesieniu do operacji bitowych na liczbach dwójkowych. Wyniki tych działań możesz
wyświetlić w dowolny sposób, na przykład tak jak to zostało zademonstrowane kilka
akapitów wcześniej.
W języku C++ dodano możliwość zmiany sposobu działania niektórych operatorów, w
szczególności dotyczy to właśnie operatora <<. Graficznie przypomina on symbol podwójnej strzałki,
więc intuicyjnie ten fragment kodu cout << "napis1" << zmienna << "napis2" << endl;
można odczytać jako rozkaz przesłania (skierowania) do obiektu cout kolejno napisu1, zmiennej,
napisu2 i znaku końca wiersza.
Na marginesie, w C++ możliwe jest też przedefiniowanie operatora + (plus) w taki sposób, że
działa jak odejmowanie, oraz zdefiniowanie własnej wersji operatora (minus) tak, aby wykonywane
było dodawanie. Niewtajemniczeni czytelnicy takiego kodu zródłowego mogą długo zastanawiać się,
dlaczego 2+2 = 0&
Jak widać we wcześniejszym przykładzie, można łączyć szeregowo kolejne operatory <<, co
znacząco ułatwia korzystanie z obiektu cout.
2
Programowanie obiektowe; © Krzysztof UrbaÅ„ski 2014
To, co zyskujemy, to brak procentów znanych z printf(& ) nie potrzeba zastanawiać się,
który typ zmiennej wymaga %d, %s, %x, %g itd. Niestety nic za darmo w przypadku bardziej
skomplikowanych napisów i użycia bardziej wyszukanych sposobów ich wyświetlania (np. liczba z
dokładnością do 4 miejsc po przecinku, poprzedzona spacjami, ze znakiem, wyrównana do
7. kolumny), printf może okazać się jednak bardziej zwięzłym i czytelniejszym rozwiązaniem.
Typowa aplikacja studencka najczęściej będzie dobrze współpracować z cout/cin.
Obiekt cin
Podobnie jak obiektowym odpowiednikiem standardowego wyjścia jest cout, tak standardowe
wejście reprezentuje obiekt o nazwie cin.
Odpowiednikiem scanf("%d", &zmienna) jest przykładowy kod (uwaga! nie zawiera on
obsługi błędów!):
int x = 0;
cin >> x;
Gdybyśmy jednak próbowali do skutku wczytać poprawną liczbę całkowitą i obsłużyć błędy
formatu, to pojawiÄ… siÄ™ pewne komplikacje w kodzie spowodowane brakiem odpowiednika funkcji
fflush(stdin). Można sobie wtedy poradzić trochę inaczej:
int x = 0;
cout << "Podaj liczbÄ™ int: ";
while(true)
{
cin >> x;
bool error = cin.fail();
cin.clear();
cin.ignore(INT_MAX, '\n');
if(error)
cout << "Spróbuj ponownie: ";
else
break;
}
cout << x << endl;
Czy pamiętasz, jak można było zabezpieczyć standardowe wejście przed błędami, gdy
używaliśmy scanf(& )? Powyższe zabezpieczenie wymaga większej liczby wierszy kodu, ale
potencjalnie daje nam też większe możliwości.
3
Programowanie obiektowe; © Krzysztof UrbaÅ„ski 2014
Zadania do realizacji na zajęciach część A
1. Jak można wczytywać pojedynczy znak przy użyciu cin? Może to być przydatne np.
w menu wyboru (1. wczytaj dane\n2. wyświetl dane\n0. koniec);
2. Spróbuj naprzemiennie używać w programie cout oraz printf. Kiedy może wystąpić
niespodziewana zmiana kolejności wyświetlania wyników w konsoli?
3. Sprawdz, w jaki sposób można formatować dane wyjściowe w cout (podobne jak to
robiliśmy w przypadku printf). Wyświetl liczbę zmiennoprzecinkową z dokładnością
do 3 cyfr znaczących, zmienną typach char jako liczbę dziesiętną, zmienną typu char
jako znak, napis wyrównany do prawej krawędzi 30-kolumnowego pola.
4. Jak można wczytywać pełne wiersze tekstu (także te, które zawierają spacje)? Wczytaj
dane do tablicy znakowej. Pamiętaj o zabezpieczeniu (nie dopuść do przepełnienia
tablicy)
char title[50] = { 0 };
cout << "Podaj tytul ksiazki: ";
//uzupełnij ten fragment kodu
cout << "Tytul: '" << title << "'" << endl;
4
Programowanie obiektowe; © Krzysztof UrbaÅ„ski 2014
Przeciążanie operatora << i hermetyzacja
class MyClass {
private:
char *t;
int i;
public:
MyClass(char *t, int i) { this.t = strup(t); this.i = i; }
~MyClass() { if(t) free(t); }
void show() { cout << t << "; " << i; }
};
void main() {
MyClass object("Abcd", 1234);
cout << "I am an object [ ";
object.show();
cout << " ]" << endl;
}
To, czego brakuje w powyższym kodzie, to bezpośrednia współpraca instancji (wcielenia,
przedstawiciela) klasy MyClass z obiektem cout.
Wygodniej byłoby zapisać powyższy kod następująco:
cout << "I am an object [ " << object << " ]" << endl;
Nasza zmienna obiektowa byłaby potraktowana wtedy podobnie jak zwykła zmienna, np.
int i, zaś wyświetlanie zmieściłoby się w jednej zwięzłej linijce kodu.
class MyClass {
friend ostream & operator<< (ostream &, MyClass &);
private:
char *t;
int i;
public:
MyClass(char *t, int i) { this.t = strup(t); this.i = i; }
~MyClass() { if(t) free(t); }
};
ostream & operator<< (ostream &str, MyClass &obj) {
stream << obj.t << "; " << obj.i;
}
void main() {
MyClass object("Abcd", 1234);
cout << "I am an object [ " << object << " ]" << endl;
}
5
Programowanie obiektowe; © Krzysztof UrbaÅ„ski 2014
#include
using namespace std;
class Wektor {
friend ostream & operator<< (ostream &, Wektor &);
private:
double x, y;
public:
Wektor(double x, double y) : x(x), y(y) {}
Wektor() : x(0.0), y(0.0) { }
Wektor operator + (Wektor b);
};
Wektor Wektor::operator + (Wektor b) {
return Wektor(this->x + b.x, this->y + b.y);
}
ostream & operator<< (ostream &strumien, Wektor &b) {
strumien << "[" << b.x << ", " << b.y << "]";
return strumien;
}
Zagadnienia do opanowania:
" Prototypy metod w klasie, definicje metod poza klasÄ….
" Uproszczona inicjalizacja pól w konstruktorze
" Przeciążony operator + wewnątrz klasy Wektor
" Przeciążony operator << na zewnętrz klasy
Zadania do realizacji na zajęciach część B
1. Dopisz fragment kodu, który zademonstruje użycie obiektów v, w będących instancjami klasy
Wektor, wyświetlając te wektory.
2. Wykonaj dodawanie wektorów (w, v) i wyświetl jego wynik.
3. Zdefiniuj klasę o nazwie Tablica, która w chwili konstrukcji dynamicznie zaalokuje miejsce na
podaną liczbę komórek typu double. Przeciąż operator << w taki sposób, aby łatwe było
wyświetlanie całej tablicy przy pomocy obiektu cout. Nie zapomnij o destruktorze
zwalniającym pamięć zaalokowaną dynamicznie.
4. Przeciąż operator [] w taki sposób, aby zadziałał jak w normalnych tablicach C, czyli:
Tablica *tab = new Tablica(300); albo Tablica tab(300);
tab[0] = 0.0; tab[1] = 1.1; itp.
cout << tab << endl;
5. Dla dociekliwych: zadbaj o obsługę błędów polegających na przekroczeniu dopuszczalnych
zakresów indeksów.
6
Programowanie obiektowe; © Krzysztof UrbaÅ„ski 2014
Wyszukiwarka
Podobne podstrony:
PO lab 9
PO lab 2
PO lab 7
PO lab 01
PO lab 8
PO lab 2
Laboratorium z PO Zestaw 02
PO lab 4
PO lab 4
Programowanie i jezyk C Lab 02
Po prostu?cess 02 XP PL ppacxp
PA lab [02] rozdział 2
PO lab 10
02 Stalinizacja życia w Polsce po II Wojnie Światowej
Kuchnia francuska po prostu (odc 02) Kiełbaski z soczewicą
Kuchnia francuska po prostu (odc 02) Kiełbaski nie całkiem w bułkach
02 lab cd kinematyka obrab do sprawozd cz 1
więcej podobnych podstron