Hampir semua program yang kita tulis sejauh ini bertumpu pada satu header yang sama: <iostream>. Header ini bukan sekadar tempat std::cout dan std::cin tinggal — di dalamnya ada sebuah keluarga kelas yang dirancang sebagai abstraksi input-output, yaitu lapisan yang menyatukan cara kita menulis ke layar, ke file, dan ke memori. Memahami petanya membuat semua topik section ini mudah tersusun: manipulator, stringstream, sampai file stream hanyalah “pemain baru” di lapangan yang sama. Pada Chapter ini kita membedah struktur <iostream>, membuktikan bahwa satu fungsi bisa menulis ke stream mana pun, dan meninjau ulang perilaku buffer yang menentukan kapan data benar-benar tiba di tujuan.

Empat Objek Stream Standar #

Begitu program dimulai, pustaka standar sudah menyiapkan empat objek global yang siap pakai tanpa deklarasi tambahan. std::cout bertipe std::ostream (output stream), std::cin bertipe std::istream (input stream), sedangkan std::cerr dan std::clog juga bertipe std::ostream — ketiga ostream hanya berbeda tujuan dan perilaku buffer.

ObjekTipeTujuanBufferPeruntukan
std::coutstd::ostreamstandard output (stdout)DibufferData keluaran utama program
std::cinstd::istreamstandard input (stdin)DibufferData masukan dari pengguna
std::cerrstd::ostreamstandard error (stderr)Tanpa bufferPesan galat yang harus segera tampil
std::clogstd::ostreamstandard error (stderr)DibufferCatatan log dan diagnostik

Kita sudah memakai cin dan cout pada Chapter Input dengan cin dan Output dengan cout di Section Dasar Pemrograman, serta menguji cerr dan clog lewat redirect pada Chapter Input-Output dengan cerr. Yang belum kita lihat adalah bagaimana keempatnya tersusun dalam satu desain yang rapi.

Peta Kelas di Balik <iostream> #

Nama-nama seperti basic_ostream terlihat rumit pada pandangan pertama, tetapi polanya sederhana: kelas-kelas inti adalah template yang bisa bekerja dengan tipe karakter apa pun, lalu pustaka standar menyediakan alias untuk versi char yang kita pakai sehari-hari. Dua baris berikut ada di header standar: using ostream = basic_ostream<char>; dan using istream = basic_istream<char>;. Jadi std::cout sebenarnya adalah objek dari kelas std::basic_ostream<char> yang diberi nama pendek std::ostream. (Pembahasan template sendiri menyusul pada Section Generic Programming dan Templates.)

Diagram di atas membaca: ios_base menyimpan pengaturan stream seperti flag format dan state galat; basic_ios menambahkan buffer dan hubungan antar stream; basic_istream menyediakan operator >>, basic_ostream menyediakan operator <<; dan basic_iostream mewarisi keduanya untuk stream yang bisa dua arah. Keluarga file (basic_ifstream, basic_ofstream, basic_fstream dari <fstream>) dan keluarga string (basic_istringstream dan kawan-kawan dari <sstream>) menempel di hirarki yang sama — itulah mengapa operator << dan >> yang kita pelajari di layar berlaku persis di file dan di memori.

Abstraksi Stream: Satu Fungsi untuk Semua Tujuan #

Kekuatan peta ini terasa saat kita menyadari bahwa fungsi tidak perlu tahu ke mana datanya pergi. Parameter bertipe std::ostream& menerima cout, cerr, clog, maupun stream file — semuanya tanpa mengubah satu baris pun di dalam fungsi. Perhatikan program berikut:

cpp
#include <iostream>
#include <string>

// Satu fungsi untuk SEMUA stream bertipe std::ostream:
// inilah kekuatan abstraksi stream di C++.
void tulis(std::ostream& keluaran, const std::string& pesan) {
    keluaran << pesan << '\n';
}

int main() {
    tulis(std::cout, "cout : saluran data (stdout, dibuffer)");
    tulis(std::cerr, "cerr : pesan galat (stderr, tanpa buffer)");
    tulis(std::clog, "clog : catatan log (stderr, dibuffer)");
    return 0;
}

Output yang Dihasilkan:

text
cout : saluran data (stdout, dibuffer)

Mengapa blok di atas hanya berisi satu baris dari tiga pemanggilan? Karena alat pengukur menangkap standard output saja: baris cerr dan clog mengalir ke standard error sehingga tidak ikut terdata. Di terminal sungguhan ketiganya tampil berurutan, dan kita bisa membuktikan jalurnya berbeda dengan redirect:

bash
$ ./peta-stream
cout : saluran data (stdout, dibuffer)
cerr : pesan galat (stderr, tanpa buffer)
clog : catatan log (stderr, dibuffer)

$ ./peta-stream 2> /dev/null
cout : saluran data (stdout, dibuffer)

$ ./peta-stream > hasil.txt 2> galat.log
$ cat hasil.txt
cout : saluran data (stdout, dibuffer)
$ cat galat.log
cerr : pesan galat (stderr, tanpa buffer)
clog : catatan log (stderr, dibuffer)

Mari kita telaah baris demi baris:

  1. Baris 1-2 (#include ...): <iostream> menghadirkan keempat objek standar beserta kelas-kelasnya; <string> kita perlukan untuk tipe parameter pesan.
  2. Baris 5-7 (void tulis(std::ostream& keluaran, ...)): fungsi menerima reference ke std::ostream — bukan salinan — sehingga ia menulis langsung ke objek stream asli yang dikirim pemanggil.
  3. Baris 6 (keluaran << pesan << '\n';): dari dalam fungsi, kita tidak tahu dan tidak peduli tujuan sebenarnya; operator << bekerja seragam berkat mekanisme virtual function yang dipelajari pada Section Pemrograman Berorientasi Objek.
  4. Baris 11-13 (tiga pemanggilan): fungsi yang sama dipanggil tiga kali dengan tiga objek berbeda. Hasilnya identik di sisi kode, tetapi sistem operasi mengarahkan masing-masing ke jalur yang berbeda.

Buffer: Dibuffer vs Tanpa Buffer #

Buffer adalah wadah sementara di memori: karakter dikumpulkan dulu, lalu dikirim sekaligus ke tujuan agar operasi tulis yang mahal tidak terjadi berulang-ulang. std::cout dan std::clog dibuffer penuh — data bisa menunggu sampai buffer penuh, sampai ada perintah flush eksplisit, atau sampai program berakhir. std::cerr memilih jalan berbeda: setiap penyisipan langsung di-flush, karena pesan galat justru paling dibutuhkan saat program terancam berhenti mendadak dan buffer cout belum sempat dikosongkan.

Ada satu keterkaitan penting yang perlu kita ingat: std::cin secara bawaan tied (diikat) ke std::cout. Sebelum cin mulai membaca, cout di-flush terlebih dahulu — itulah sebabnya prompt seperti Masukkan umur: selalu tampil sebelum program menunggu ketikan, tanpa perlu endl manual. Detail flush dan manipulator terkait akan kita bedah tuntas pada Chapter Manipulator.

Peta <iostream> kini utuh di tangan kita: satu hirarki kelas, empat objek siap pakai, satu operator << yang berlaku di mana saja. Chapter berikutnya memakai peta ini untuk tujuan yang sangat praktis — membuat output numerik tampil rapi lewat lebar kolom, presisi, dan std::format yang menjadi cara modern C++.

Referensi #