Chapter sebelumnya berakhir dengan galat 'sapa' was not declared in this scope ketika fungsi dipanggil sebelum definisinya dibaca compiler. Kabar baiknya, C++ memisahkan dua hal yang di Chapter lalu kita anggap satu: memperkenalkan nama fungsi (deklarasi) dan menyediakan badan fungsinya (definisi). Deklarasi singkat bernama function prototype ini adalah kunci yang membuat urutan penulisan tidak lagi menjadi hambatan. Pada Chapter ini kita membedah keduanya, membuktikan prototipe menyelesaikan masalah urutan, dan mencicipi praktik profesional: menaruh prototipe di header.
Deklarasi vs Definisi #
Deklarasi memperkenalkan nama dan tanda tangan fungsi — return type, nama, dan parameter list — tanpa badan, ditutup titik koma. Definisi menyediakan deklarasi SEKALIGUS badan fungsi; ia adalah deklarasi yang diberi isi. Program berikut mendeklarasikan dua fungsi di atas main(), lalu mendefinisikannya di bawah:
#include <iostream>
#include <string>
// Prototipe: deklarasi tanpa badan fungsi, ditutup titik koma
int jumlahkan(int a, int b);
void sapa(std::string nama);
int main() {
std::cout << "3 + 4 = " << jumlahkan(3, 4) << "\n";
sapa("Budi");
return 0;
}
// Definisi lengkap: boleh ditulis SETELAH main()
int jumlahkan(int a, int b) {
return a + b;
}
void sapa(std::string nama) {
std::cout << "Halo, " << nama << "!\n";
}Output yang Dihasilkan:
3 + 4 = 7
Halo, Budi!Tiga hal penting dari kode di atas: Baris 6-7 adalah prototipe — tanda tangan fungsi lengkap dengan titik koma, tanpa kurung kurawal; mereka menjanjikan “fungsi bernama ini ada, bentuknya begini, badannya menyusul”. Baris 10-11 kini sah karena compiler sudah membaca janjinya — ia memanggil fungsi dengan percaya diri dan membiarkan linker menyatukan pemanggilan dengan definisinya pada tahap akhir kompilasi. Baris 14-21 memenuhi janji itu dengan definisi lengkap. Prototipe harus cocok dengan definisinya: return type, nama, dan tipe parameter yang sama persis, sebab kalau tidak, linker akan mengeluh undefined reference — galat yang pernah kita lihat pada Chapter Proses Kompilasi dan Linking.
Mengapa Prototipe Dibutuhkan #
Dengan prototipe, urutan definisi menjadi bebas: definisi boleh di atas, di bawah main(), atau bahkan di file lain. Manfaat ini terasa nyata dalam dua situasi. Pertama, keterbacaan: banyak programmer menyukai main() yang pendek dan berada di bagian atas file sebagai peta program, lalu definisi fungsi menyusul di bawahnya. Kedua, dan lebih mendasar: dua fungsi yang saling memanggil — misalnya cekGenap memanggil cekGanjil dan sebaliknya — mustahil diurutkan tanpa prototipe, karena salah satunya pasti “belum dikenal” saat didefinisikan.
Satu aturan yang perlu dijaga: prototipe adalah janji, jadi pastikan janji itu dipenuhi. File yang berisi prototipe tanpa definisi tetap berhasil dikompilasi, tetapi gagal saat di-link bila fungsinya benar-benar dipanggil. Dua nama lain yang akan sering Anda temui di literatur: forward declaration untuk deklarasi maju seperti ini, dan function signature untuk tanda tangan fungsinya.
Prototipe di Header: Sekilas #
Praktik profesional menaruh prototipe ke dalam file header, sehingga banyak file .cpp bisa memakai fungsi yang sama tanpa menyalin prototypenya satu per satu. Kita sudah mengenal #include pada Chapter Header dan Include; kini header lokal kita isi janji fungsi. File matematika.h berikut akan disertakan dalam bundle Chapter ini:
#ifndef MATEMATIKA_H
#define MATEMATIKA_H
// Prototipe tinggal di header, siap dipakai banyak file .cpp
double luasPersegi(double sisi);
double luasLingkaran(double jari);
#endifBaris #ifndef/#define/#endif disebut include guard: pencegah header yang sama disisipkan dua kali dalam satu file, sebab deklarasi ganda fungsi yang identik sebenarnya boleh, tetapi kebiasaan menjaga header tetap aman jauh lebih baik dibangun sejak sekarang. File aplikasi-hitung.cpp di bundle meng-include header itu dan mendefinisikan fungsi yang dijanjikannya:
#include <iostream>
#include "matematika.h"
int main() {
std::cout << "Luas persegi sisi 5: " << luasPersegi(5.0) << "\n";
std::cout << "Luas lingkaran r=7: " << luasLingkaran(7.0) << "\n";
return 0;
}
// Definisi fungsi yang dijanjikan matematika.h
double luasPersegi(double sisi) {
return sisi * sisi;
}
double luasLingkaran(double jari) {
const double PI = 3.141592653589793;
return PI * jari * jari;
}Output yang Dihasilkan:
Luas persegi sisi 5: 25
Luas lingkaran r=7: 153.938Perhatikan #include "matematika.h" memakai tanda kutip, bukan kurung siku — tanda kutip berarti “cari file ini di folder proyek”, sedangkan kurung siku untuk header standar. Untuk proyek kecil, definisi fungsi masih kita taruh di file .cpp yang sama seperti di atas; pemisahan penuh header berisi deklarasi dan source berisi definisi akan kita rapikan pada Section Build System dan Project Structure, setelah alat build-nya kita kenal. Yang perlu dibawa dari sini: prototipe di header adalah kontrak yang bisa dipakai lintas file.
Rujukan resmi: cppreference: functions dan cppreference: definitions dan ODR . Dengan kontrak fungsi sudah utuh, kita kini siap membahas masukannya lebih dalam: parameter dan argumen.