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.
| Objek | Tipe | Tujuan | Buffer | Peruntukan |
|---|---|---|---|---|
std::cout | std::ostream | standard output (stdout) | Dibuffer | Data keluaran utama program |
std::cin | std::istream | standard input (stdin) | Dibuffer | Data masukan dari pengguna |
std::cerr | std::ostream | standard error (stderr) | Tanpa buffer | Pesan galat yang harus segera tampil |
std::clog | std::ostream | standard error (stderr) | Dibuffer | Catatan 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:
#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:
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:
$ ./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:
- Baris 1-2 (
#include ...):<iostream>menghadirkan keempat objek standar beserta kelas-kelasnya;<string>kita perlukan untuk tipe parameterpesan. - Baris 5-7 (
void tulis(std::ostream& keluaran, ...)): fungsi menerima reference kestd::ostream— bukan salinan — sehingga ia menulis langsung ke objek stream asli yang dikirim pemanggil. - 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. - 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++.