Podrozdziały


2.2 Proste operacje We/Wy

Po dołączeniu do naszego programu pliku nagłówkowego iostream zdefiniowane są (lub tylko zadeklarowane, ale to na razie nie jest dla nas istotne), między innymi, identyfikatory coutcin. Są to nazwy obiektów reprezentujących standardowe strumienie: wejściowy (ang. standard input stream, stdin) i wyjściowy (ang. standard output stream, stdout).


2.2.1 Wyprowadzanie danych

Obiekt cout, jak powiedzieliśmy, reprezentuje standardowy strumień wyjściowy. Jest to predefiniowany obiekt klasy ostream, której definicja jest widoczna dzięki dołączeniu pliku nagłówkowego iostream. Strumień wyjściowy to strumień danych wyprowadzanych z programu do „świata zewnętrznego”, który to świat jest w tym wypadku tożsamy z ekranem komputera. Skrót cout należy rozumieć jako console output i wymawiać si-aut (porównując z Javą, najbliższym odpowiednikiem cout jest obiekt System.out). Ponieważ cout jest obiektem, można na jego rzecz wywoływać metody zdefiniowane w jego klasie. Metody te poznamy w rozdziale o operacjach WE/WY . Na razie nie musimy ich znać, aby zacząć obiektu cout używać: dla wygody programisty został bowiem dostarczony mechanizm wstawiania do strumienia za pomocą operatora '<<' (dwa znaki mniejszości, bez odstępu pomiędzy nimi). Konstrukcja jest taka jak w linii  programu z pliku helloWorld.cpp. Piszemy więc

       cout << "Hello, World" << endl;
aby wstawić napis, podany tu dosłownie jako literał, do strumienia „płynącego” na ekran, reprezentowany tu przez cout. Następnie, po kolejnej parze znaków '<<', do tego samego strumienia wstawiamy coś, czego identyfikatorem jest endl. Ta nazwa nie jest ujęta w cudzysłowy, bo nie chcemy zobaczyć na ekranie napisu " endl". Jest to tzw. manipulator (zdefiniowany również dzięki dołączeniu pliku nagłówkowego iostream). Jego wstawienie do strumienia wyjściowego powoduje dodanie znaku nowej linii. Gdybyśmy endl nie dodali, to znak nowej linii nie byłby wyprowadzony i następna operacja pisania na ekran kontynuowana byłaby w tym samym wierszu. Podobny efekt moglibyśmy osiągnąć dodając znak nowej linii do samego napisu: '"Hello, World\n"'. Dwuznak '\n' pojawiający się wewnątrz napisu oznacza właśnie znak nowej linii. Efekt byłby podobny, ale nie identyczny: wstawienie manipulatora endl powoduje dodatkowo natychmiastowe opróżnienie bufora wyjściowego i wyprowadzenie napisu na ekran. Bez niego natomiast napis nie musi być wyprowadzony natychmiast: system może zaczekać, aż w buforze wyjściowym uzbiera się więcej danych i wyprowadzić je dopiero wtedy łącznie.

W tym przykładzie wstawiliśmy do strumienia dwa elementy (obiekty): napis i manipulator. Moglibyśmy wstawić ich więcej. Zauważmy jednak, że wstawianie danych do strumienia wyjściowego odbywa się pojedynczo: każda dana musi być poprzedzona znakami '<<'. A zatem np. nie można oddzielać poszczególnych elementów przecinkami

       cout << "Hello, World" , endl; // NIE!!!
Prawidłowa jest natomiast konstrukcja
       cout << "Pierwsza linia,"    << endl
            << "druga linia,"       << endl
            << "i w koncu trzecia." << endl;
która jest, zauważmy, jedną instrukcją, wyprowadzającą na ekran trzy napisy i trzy znaki końca linii.

Znający Javę pamiętają, że jest tam dozwolona konstrukcja

       int k = 7;
       double x = 8.6;
       System.out.println(k);
       System.out.println(x);
Te instrukcje spowodują wypisanie na ekran liczb 7 i 8.6, mimo że typ argumentu jest w obu przypadkach inny, a w żadnym nie jest odniesieniem do obiektu klasy String. Dzieje się tak dzięki przeciążeniu metody println. Podobny mechanizm działa w C++ dla operatora '<<'. Wstawiać do strumienia możemy nie tylko napisy, ale zmienne typów wbudowanych lub innych, dla których działanie operatora '<<' zostało zdefiniowane, jak np. obiekty klasy string w przykładzie poniżej:


P3: jan.cpp     Operator '$ \ll$'

      1.  #include <iostream>
      2.  #include <string>
      3.  using namespace std;
      4.  
      5.  int main() {
      6.      double waga = 76.5;
      7.      int  wzrost = 182;
      8.      string imie = "Jan";
      9.      cout << imie   << " wazy " << waga << " kg i ma "
     10.           << wzrost << " cm wzrostu."  << endl;
     11.  }

Programik powyższy wypisuje, jak łatwo się domyślić, napis

    Jan wazy 76.5 kg i ma 182 cm wzrostu.
Klasa string, użyta w tym przykładzie, zostanie omówiona w rozdziale o napisach w C++ . Inne nowe elementy tego przykładu omówimy bardziej szczegółowo za chwilę.


2.2.2 Wprowadzanie danych

Wprowadzanie danych odbywa się za pomocą podobnego mechanizmu. Tym razem obiektem reprezentującym strumień informacji wchodzących do programu ze świata zewnętrznego jest obiekt cin z klasy istream, dostępnej dzięki dołączeniu pliku iostream. Źródłem tej informacji jest domyślnie klawiatura komputera. Nazwa cin pochodzi od console input (i wymawiać ją należy si-in). Jak cout, również cin jest obiektem, a zatem można na jego rzecz wywoływać metody zdefiniowane w jego klasie. Na razie jednak będziemy korzystać głównie z mechanizmu wyjmowania ze strumienia za pomocą operatora '>>' (dwa znaki większości, bez żadnego odstępu pomiędzy nimi).


P4: czyt.cpp     Operator '$ \gg$'

      1.  #include <iostream>
      2.  #include <string>
      3.  using namespace std;
      4.  
      5.  int main() {
      6.      string imie;
      7.      int wzrost;
      8.      double waga;
      9.      cout << "Podaj imie, wzrost i wage: ";
     10.      cin  >> imie >> wzrost >> waga;
     11.      cout << imie << ", masz " << wzrost  << " cm wzrostu "
     12.           << "i wazysz " << waga << " kg" << endl;
     13.  }

Wykonanie programu miało następujący przebieg:

    cpp> ./czyt
    Podaj imie, wzrost i wage: Tomasz 182 76.5
    Tomasz, masz 182 cm wzrostu i wazysz 76.5 kg
    cpp>

Zauważmy tu następujące fakty:

Operacje czytania i pisania, a więc operacje wejścia i wyjścia, należą do najbardziej zawiłych prawie w każdym języku programowania. W szczególności, dotyczy to czytania z klawiatury, ze względu na nieprzewidywalność zachowań użytkowników... Tak jest i w C++. Szczegóły odłożymy więc do rozdziału o operacjach we/wy .

T.R. Werner, 21 lutego 2016; 20:17