Fungsi adalah unit terkecil untuk mengorganisir logika algoritma. Dengan fungsi, kita memecah masalah besar menjadi langkah-langkah kecil yang dapat diuji secara terpisah, diberi nama yang menjelaskan maksudnya, dan dipakai ulang. Pada Chapter ini kita akan mempelajari cara mendefinisikan fungsi, cara melewatkan parameter (by value, by reference, by const reference), cara membebani nama fungsi, serta pengantar rekursi yang menjadi pondasi banyak algoritma DSA.
Definisi Fungsi #
Sebuah fungsi C++ terdiri dari return type, nama, daftar parameter dalam tanda kurung, dan badan fungsi dalam {}. Compiler harus melihat deklarasi fungsi sebelum digunakan, sehingga biasanya fungsi didefinisikan di atas main atau dideklarasikan dulu sebagai prototype di header.
Mekanisme: Parameter dan Return Value #
Saat fungsi dipanggil, argumen disalin ke parameter lokal fungsi (pass by value). Saat fungsi menjalankan return, nilai dikirim kembali ke pemanggil dan parameter lokal dihancurkan.
Kode: Fungsi Penjumlahan Sederhana #
#include <iostream>
int tambah(int a, int b) {
return a + b;
}
int main() {
int x = 10, y = 5;
std::cout << "10 + 5 = " << tambah(x, y) << '\n';
return 0;
}Output yang Dihasilkan:
10 + 5 = 15- Baris
int tambah(int a, int b): return typeint, dua parameterint. Nama fungsitambah. - Baris
return a + b;: hasil ekspresi dikirim ke pemanggil. Setelah return, parameteradanbdihancurkan. - Baris
tambah(x, y): nilaixdisalin kea,ydisalin keb. Variabelxdanydimaintidak terpengaruh.
Pass by Value vs Reference vs Const Reference #
Cara melewatkan parameter menentukan apakah fungsi bisa memodifikasi variabel pemanggil dan seberapa mahal operasi copy-nya. Tiga varian utama:
| Varian | Sintaks | Modifikasi? | Copy mahal? |
|---|---|---|---|
| By value | int a | Tidak (copy) | Ya |
| By reference | int& a | Ya | Tidak |
| By const reference | const int& a | Tidak | Tidak |
Kode: Perbandingan Tiga Varian #
#include <iostream>
#include <vector>
int tambah_salin(int a, int b) { // pass by value
a = a + b;
return a;
}
void tambah_ref(int& a, int b) { // pass by reference
a = a + b;
}
long long sum(const std::vector<int>& v) { // const reference
long long total = 0;
for (int x : v) total += x;
return total;
}
int main() {
int x = 10;
int hasil_val = tambah_salin(x, 5);
std::cout << "setelah salin: x=" << x << " hasil=" << hasil_val << '\n';
tambah_ref(x, 5);
std::cout << "setelah ref: x=" << x << '\n';
std::vector<int> data{1, 2, 3, 4, 5};
std::cout << "sum = " << sum(data) << '\n';
return 0;
}Output yang Dihasilkan:
setelah salin: x=10 hasil=15
setelah ref: x=15
sum = 15- Fungsi
tambah_salin(int a, int b):aadalah copy darix. Memodifikasiatidak memengaruhixdimain. Setelah pemanggilan,xtetap10. - Fungsi
tambah_ref(int& a, int b):aadalah alias darix. Memodifikasiasama dengan memodifikasixlangsung. Setelah pemanggilan,xmenjadi15. - Fungsi
sum(const std::vector<int>& v):vadalah referensi const — tidak ada copy vector (yang mahal), tetapi fungsi tidak bisa memodifikasi elemenv.
Default Argument #
C++ mengizinkan parameter memiliki nilai default bila tidak disediakan pemanggil. Default harus berada di posisi paling kanan daftar parameter.
Kode: Fungsi Pangkat dengan Default #
#include <iostream>
int pangkat(int base, int exp = 2) {
int hasil = 1;
for (int i = 0; i < exp; ++i) hasil *= base;
return hasil;
}
int main() {
std::cout << "pangkat(3) = " << pangkat(3) << '\n'; // 3^2
std::cout << "pangkat(3,4) = " << pangkat(3, 4) << '\n'; // 3^4
return 0;
}Output yang Dihasilkan:
pangkat(3) = 9
pangkat(3,4) = 81- Baris
int exp = 2: parameterexpmemiliki default2. Pemanggil boleh tidak menyediakan argumen kedua. - Baris
pangkat(3): hanya satu argumen;expotomatis2, menghitung3^2 = 9. - Baris
pangkat(3, 4): dua argumen disediakan; default ditimpa, menghitung3^4 = 81.
Function Overloading #
C++ mengizinkan beberapa fungsi berbagi nama asalkan parameter berbeda (jumlah atau tipe). Compiler memilih versi yang tepat berdasarkan tipe argumen saat pemanggilan.
Kode: Overload maks untuk int dan double #
#include <iostream>
int maks(int a, int b) {
return (a > b) ? a : b;
}
double maks(double a, double b) {
return (a > b) ? a : b;
}
int main() {
std::cout << "maks(int) = " << maks(7, 12) << '\n';
std::cout << "maks(double) = " << maks(3.5, 2.1) << '\n';
return 0;
}Output yang Dihasilkan:
maks(int) = 12
maks(double) = 3.5- Baris
maks(7, 12): kedua argumen bertipeint, compiler memilih overloadint maks(int, int). - Baris
maks(3.5, 2.1): argumen bertipedouble, compiler memilih overloaddouble maks(double, double). - Overload tidak boleh hanya berbeda di return type — daftar parameter harus berbeda.
Rekursi Dasar #
Rekursi adalah teknik di mana fungsi memanggil dirinya sendiri untuk menyelesaikan sub-masalah yang lebih kecil. Banyak algoritma DSA — tree traversal, merge sort, backtracking — secara natural diekspresikan secara rekursif.
Mekanisme: Base Case dan Recursive Case #
Setiap fungsi rekursif wajib memiliki base case (kasus dasar yang berhenti) dan recursive case (panggilan diri sendiri dengan input lebih kecil). Tanpa base case, rekursi berjalan selamanya hingga stack overflow.
Kode: Factorial Rekursif #
#include <iostream>
long long factorial(int n) {
if (n <= 1) return 1; // base case
return n * factorial(n - 1); // recursive case
}
int main() {
std::cout << "factorial(5) = " << factorial(5) << '\n';
return 0;
}Output yang Dihasilkan:
factorial(5) = 120- Baris
if (n <= 1) return 1;: base case. Saatnmencapai1, rekursi berhenti dan mengembalikan1. Tanpa baris ini, fungsi akan memanggil dirinya hinggansangat negatif dan stack overflow. - Baris
return n * factorial(n - 1);: recursive case. Sub-masalah lebih kecil (n-1) diselesaikan dulu, lalu dikalikann. - Untuk
n = 5, urutan pemanggilan:5 * factorial(4) = 5 * 4 * factorial(3) = ... = 5 * 4 * 3 * 2 * 1 = 120.
Ringkasan #
- Fungsi memecah algoritma menjadi unit yang dapat diuji dan dipakai ulang.
- Pass by value aman tapi copy mahal; by reference untuk modifikasi; by const reference untuk efisiensi read-only.
- Default argument mengurangi duplikasi overload; tempatkan default di kanan.
- Overload memungkinkan satu nama dengan beberapa perilaku berdasarkan tipe argumen.
- Rekursi butuh base case yang jelas; waspadai stack overflow pada kedalaman besar.