Pada chapter-chapter sebelumnya, setiap object yang kita buat harus diisi manual: kita memanggil buka() untuk rekening atau menugaskan panjang dan lebar satu per satu. Cara ini rapuh — siapa pun yang lupa mengisi bisa memakai object dengan data yang belum lengkap. C++ menyediakan constructor, fungsi khusus yang dijalankan secara otomatis tepat saat object dibuat, sehingga object tidak pernah sempat hidup dalam keadaan kosong. Chapter ini membahas cara menulisnya dan bagaimana satu class bisa punya beberapa constructor sekaligus.

Apa itu Constructor #

Constructor adalah member function yang tugasnya menginisialisasi object: mengisi data member agar state awalnya valid. Ia punya tiga ciri yang membedakannya dari fungsi biasa. Pertama, namanya persis sama dengan nama class — constructor dari class Produk pasti bernama Produk. Kedua, ia tidak punya return type, bahkan bukan void; kita tidak menulis apa pun sebelum namanya. Ketiga, dan paling penting, ia dipanggil otomatis oleh compiler pada saat object dibuat — kita tidak pernah memanggilnya lewat . seperti fungsi biasa.

Karena dijalankan otomatis, constructor adalah satu-satunya tempat yang dijamin dieksekusi untuk setiap object. Inilah posisi strategisnya: semua aturan awal — nilai default, validasi argumen, pencatatan ke log — tinggal kita tulis di sana sekali. Lupakan constructor, dan setiap pembuatan object harus mengandalkan disiplin pemanggil yang tidak selalu ada.

Beberapa Constructor dalam Satu Class #

Sering kali object perlu dibuat dengan berbagai tingkat kelengkapan: ada yang dibuat lengkap, ada yang sengaja dibuat kosong untuk diisi belakangan. C++ mengizinkan kita menulis beberapa constructor dalam satu class, asalkan daftar parameternya berbeda jumlah atau tipe — persis konsep function overloading yang sudah kita kenal. Compiler kemudian memilih constructor yang cocok berdasarkan argumen yang kita kirim saat pembuatan object.

cpp
class Produk {
public:
    Produk();                                   // constructor tanpa parameter
    Produk(const std::string& n);               // constructor satu parameter
    Produk(const std::string& n, double h, int s);
};

Ketiga constructor di atas hidup berdampingan dan saling melengkapi. Tidak ada yang “menang” — keputusan diambil baris demi baris di titik pembuatan object. Inilah yang membuat API class nyaman dipakai: pemanggil bebas memilih tingkat detail yang ia butuhkan.

Contoh: Tiga Constructor yang Dipilih Compiler #

Program berikut mendefinisikan ketiga constructor Produk, lengkap dengan jejak cetak agar kita melihat constructor mana yang benar-benar dieksekusi:

cpp
#include <iostream>
#include <string>

class Produk {
public:
    std::string nama;     // tanpa in-class initializer
    int stok = 0;         // in-class initializer: nilai default
    double harga = 0.0;

    // Constructor 1: tanpa parameter
    Produk() {
        nama = "Tanpa Nama";
        std::cout << "Produk() dipanggil\n";
    }

    // Constructor 2: satu parameter
    Produk(const std::string& n) {
        nama = n;
        std::cout << "Produk(nama) dipanggil\n";
    }

    // Constructor 3: tiga parameter
    Produk(const std::string& n, double h, int s) {
        nama = n;
        harga = h;
        stok = s;
        std::cout << "Produk(nama, harga, stok) dipanggil\n";
    }

    void cetak() {
        std::cout << nama << " | Rp" << harga << " | stok " << stok << "\n";
    }
};

int main() {
    Produk a;                  // memanggil Produk()
    Produk b("Kopi Gayo");     // memanggil Produk(const std::string&)
    Produk c("Gula Pasir", 15500.0, 40);

    a.cetak();
    b.cetak();
    c.cetak();

    return 0;
}

Output yang Dihasilkan:

text
Produk() dipanggil
Produk(nama) dipanggil
Produk(nama, harga, stok) dipanggil
Tanpa Nama | Rp0 | stok 0
Kopi Gayo | Rp0 | stok 0
Gula Pasir | Rp15500 | stok 40

Mari kita bedah:

  1. Baris 11-15 (Produk() { ... }): constructor tanpa parameter. Baris pertama output membuktikan ia dijalankan otomatis saat Produk a; dieksekusi — tidak ada satu pun pemanggilan eksplisit di main().
  2. Baris 18-22 (Produk(const std::string& n)): constructor satu parameter. Parameter dilewatkan sebagai const std::string& agar string tidak disalin secara tidak perlu — kebiasaan baik yang sudah kita kenal dari materi fungsi.
  3. Baris 25-33 (Produk(const std::string& n, double h, int s)): constructor paling lengkap; ia mengisi seluruh data member dari argumen pemanggil.
  4. Baris 41-43 (pembuatan a, b, c): compiler memilih constructor berdasarkan argumen — nol argumen ke Produk(), satu string ke overload kedua, tiga nilai ke overload ketiga. Tiga baris jejak pertama pada output adalah buktinya.
  5. Baris 45-47 (pemanggilan cetak()): memperlihatkan state akhir. Perhatikan b: constructor keduanya hanya mengisi nama, sehingga harga dan stok memakai in-class initializer dari baris 7-8 — hasilnya Rp0 dan stok 0, bukan nilai acak.

Jejak cetak di constructor pada contoh ini adalah alat belajar. Pada kode produksi, constructor biasanya diam saja dan hanya mengisi data — tetapi pola “cetak untuk membuktikan urutan” akan terus kita pakai, misalnya saat membahas destructor.

Sekarang kita punya constructor tanpa parameter dan constructor berparameter. Chapter berikutnya memfokuskan pada yang pertama: default constructor, termasuk pertanyaan yang sering mengganggu — apa yang terjadi bila kita tidak menulisnya sama sekali.

Rujukan resmi: Constructors (cppreference) .