Argumen default adalah nilai yang dipakai parameter apabila pemanggil tidak mengirimkan argumennya. Fitur ini mempersingkat pemanggilan yang berulang dengan pengaturan sama, tanpa menghapus kemampuan menyesuaikan perilaku fungsi apabila diperlukan. Topik ini membahas cara menetapkannya, aturan penempatannya, interaksinya dengan function overloading, dan jebakan yang menyertainya.
Menetapkan nilai default parameter#
Nilai default dituliskan pada daftar parameter dengan tanda sama dengan. Parameter yang diberi default boleh tidak dikirim saat pemanggilan, sedangkan parameter lain tetap wajib dikirim. Program berikut memakai satu fungsi untuk tiga bentuk pemanggilan.
#include <iostream>
#include <string>
void cetakLaporan(std::string judul, int jumlahBaris = 3, char pengisi = '-') {
std::cout << judul << '\n';
for (int i = 0; i < jumlahBaris; ++i) {
std::cout << pengisi;
}
std::cout << '\n';
}
int main() {
cetakLaporan("Rekap nilai ujian");
cetakLaporan("Rekap kehadiran", 5);
cetakLaporan("Daftar hadir", 4, '=');
return 0;
}Rekap nilai ujian
---
Rekap kehadiran
-----
Daftar hadir
====Pemanggilan pertama hanya mengirim judul, sehingga jumlahBaris memakai 3 dan pengisi memakai tanda hubung. Pemanggilan berikutnya menimpa default satu per satu dari kiri ke kanan. C++ tidak menyediakan cara melompati parameter di tengah, sehingga ingin mengubah pengisi saja berarti mengirim jumlahBaris juga.
Nilai default dievaluasi pada saat pemanggilan, bukan saat program dikompilasi. Ekspresi apa pun yang sah sebagai inisialisasi boleh dipakai, termasuk pemanggilan fungsi lain, dengan syarat fungsi itu sudah dideklarasikan lebih dahulu. Meskipun demikian, nilai konstanta yang sederhana lebih mudah dinalar daripada default yang berubah-ubah.
Argumen default juga menjadi alat menjaga kompatibilitas. Apabila fungsi yang sudah dipakai di banyak tempat membutuhkan parameter baru, parameter itu ditambahkan di posisi terakhir beserta defaultnya, sehingga seluruh pemanggilan lama tetap dikompilasi tanpa perubahan. Pemanggilan baru kemudian mengirimkan nilai tambahan tersebut sesuai kebutuhan.
Aturan penempatan dan deklarasinya#
Parameter yang diberi default wajib berada di urutan paling belakang. Setelah satu parameter memakai default, seluruh parameter di belakangnya juga wajib memakai default, karena compiler memetakan argumen ke parameter secara berurutan.
// tidak-dijalankan
void buatLaporan(std::string judul = "Rekap", int jumlahBaris) {
// error: parameter tanpa default tidak boleh mengikuti yang berdefault
}Dalam program satu berkas, default dituliskan pada deklarasi fungsinya. Perhatian berpindah tempat ketika prototipe dipisahkan ke header, karena default hanya boleh dinyatakan satu kali dalam satu unit penerjemahan.
// tidak-dijalankan
void cetakGaris(int panjang = 20);
void cetakGaris(int panjang = 20) {
for (int i = 0; i < panjang; ++i) {
std::cout << '-';
}
std::cout << '\n';
}Konsistensi default antarunit penerjemahan juga wajib dijaga apabila header yang sama dipakai di banyak tempat. Selama default hanya dituliskan di header, semua pemakai melihat nilai yang sama, dan perubahan default cukup dilakukan satu kali. Aturan ini menjadi makin penting bersama bertambahnya jumlah berkas pada proyek.
Interaksi dengan overloading#
Argumen default dan function overloading sama-sama mempersingkat pemanggilan, tetapi keduanya bisa saling menutupi. Apabila overload cetak(int) berdampingan dengan overload cetak(int, int) yang kedua parameternya berdefault, pemanggilan cetak(7) cocok dengan kedua overload tersebut dan compiler menolaknya sebagai panggilan ambigu.
// tidak-dijalankan
#include <iostream>
void cetak(int nilai) {
std::cout << "versi tunggal: " << nilai << '\n';
}
void cetak(int nilai, int pengali = 1) {
std::cout << "versi pengali: " << nilai * pengali << '\n';
}
int main() {
cetak(7);
return 0;
}Error yang muncul berbunyi call of overloaded 'cetak(int)' is ambiguous, dan tidak ada pemulihan selain mengubah salah satu overload. Cara paling bersih adalah menghilangkan parameter default pada overload kedua, sehingga jumlah argumen langsung menentukan overload yang dipilih. Kombinasi argumen default dan overloading tetap sah, selama setiap bentuk pemanggilan hanya cocok dengan satu kandidat. Aturan praktisnya, pilih satu fitur untuk satu tugas. Apabila variasi perilaku hanya berupa nilai alternatif, default cukup, sedangkan variasi berupa alur kerja yang berbeda lebih tepat menjadi overload terpisah.
Bentuk ambigu semacam ini tidak selalu terlihat seketika karena muncul dari dua fitur yang ditulis di tempat berbeda. Kompilasi seluruh proyek dengan tingkat peringatan tinggi membantu, tetapi deteksinya tetap milik compiler saat resolusi overload berlangsung. Karena itu kedua fitur ini ditinjau bersama pada setiap perubahan antarmuka.
Kapan argumen default dipilih#
Argumen default paling tepat untuk parameter yang nilainya sama pada hampir semua pemanggilan, misalnya lebar laporan atau karakter pemisah. Apabila setengah pemanggilan memakai satu nilai dan setengah lainnya memakai nilai lain, default malah menyembunyikan keputusan yang penting, sehingga lebih jelas dinyatakan sebagai argumen eksplisit di setiap pemanggilan.
Parameter yang menentukan kebenaran hasil juga tidak layak diberi default. Nilai yang wajib dikirim pemanggil menegaskan bahwa fungsinya tidak berjalan bila informasi itu tidak ada, sedangkan default membuat fungsi seolah lengkap padahal sebagian masukannya ditebak. Prinsipnya, default hanya untuk perilaku yang aman dan wajar bagi seluruh pemakai fungsi.
Ukuran antarmuka juga perlu dijaga. Rangkaian parameter yang panjang dengan banyak default menandakan fungsi mengerjakan terlalu banyak hal, dan kondisi semacam ini lazimnya dijawab dengan beberapa fungsi kecil yang fokusnya tunggal. Fungsi yang lebih kecil lebih mudah diuji, dan pemanggilnya tidak perlu mengingat urutan parameter yang panjang. Nilai default juga sebaiknya tidak membawa asumsi tentang urutan pemanggilan, karena fungsi harus tetap benar untuk semua kombinasi argumen yang sah.
Kesalahan umum#
Menuliskan default di dua tempat adalah kesalahan yang paling sering pada proyek banyak berkas. Praktiknya, default ditempatkan pada prototipe di header, sedangkan definisi di berkas .cpp menuliskan daftar parameter tanpa default sama sekali. Kesepakatan ini menjaga satu sumber kebenaran bagi semua pemakai fungsi.
Kesalahan berikutnya adalah mengira default bisa dilewati di tengah pemanggilan. Tidak ada sintaks untuk mengirim argumen ketiga sembari melompati yang kedua, sehingga kebutuhan semacam itu ditangani dengan function overloading, bukan dengan default. Merombak urutan parameter fungsi yang sudah dipakai di banyak tempat juga berisiko, karena pergeseran posisi mengubah makna argumen yang terkirim.
Jebakan di atas muncul dari satu akar yang sama, yaitu default yang diperlakukan sebagai bagian tersembunyi dari tanda tangan fungsi. Default yang tidak terlihat pada lokasi pemanggilan membuat pembaca kode mengira fungsi dipanggil tanpa argumen. Dokumentasi fungsi tetap mencantumkan setiap default beserta artinya agar pemakaiannya jelas, dan perubahan default pada versi berikutnya diberitahukan kepada seluruh pemanggil.
Ringkasan#
- Nilai default menutupi argumen yang tidak dikirim pemanggil, dan dievaluasi pada saat pemanggilan.
- Parameter default wajib menghuni urutan paling belakang, dan default hanya boleh dinyatakan satu kali, lazimnya pada prototipe di header.
- Default yang membuat dua overload sama-sama cocok menghasilkan panggilan ambigu, sehingga keduanya dirancang berpisahan.
Referensi#
- Default arguments — cppreference.com — Kaidah penulisan dan evaluasi argumen default pada C++.
- Default arguments — LearnCpp — Penjelasan parameter default beserta jebakan penempatannya.