Menu

Constructor C++: Menginisialisasi Objek dengan Benar

Constructor adalah member function khusus yang berjalan saat objek dibuat. Pelajari default constructor, parameterized constructor, copy constructor, member initializer list, dan cara agar objek tidak tertinggal setengah terinisialisasi.

Halaman ini dilengkapi editor yang bisa dijalankan. Edit, jalankan, dan lihat output-nya seketika.

Apa Itu Constructor

Di halaman sebelumnya kamu mendefinisikan class dan memberinya member variable. Namun member pada objek yang baru dibuat berisi sampah apa pun yang ada di memori itu, kecuali kamu mengisinya. Constructor mengatasi hal ini: ia adalah member function khusus yang berjalan otomatis saat objek dibuat, dan satu-satunya tugasnya adalah meninggalkan objek dalam keadaan yang valid dan terinisialisasi penuh.

Constructor punya nama yang sama dengan class-nya dan tidak punya tipe kembalian, bahkan bukan void. Kamu tidak pernah memanggilnya secara langsung; compiler memanggilkannya untukmu setiap kali sebuah objek muncul.

Counter() yang tanpa parameter disebut default constructor, yaitu constructor yang dipakai saat kamu membuat objek tanpa memberikan argumen.

Parameterized Constructor

Constructor tanpa argumen memang cukup, tetapi biasanya kamu ingin membuat objek dengan nilai tertentu. Parameterized constructor menerima argumen dan memakainya untuk menginisialisasi member.

Sebuah class boleh punya lebih dari satu constructor, asalkan daftar parameternya berbeda. Ini sama dengan function overloading biasa, hanya saja diterapkan pada constructor. Di sini Point bisa dibuat dengan atau tanpa koordinat:

Jebakan yang umum: Point p(); tidak membuat objek. Compiler membacanya sebagai deklarasi fungsi bernama p yang mengembalikan Point. Untuk memanggil default constructor, tulis Point p; (tanpa tanda kurung) atau Point p{}; dengan kurung kurawal.

Member Initializer List

Sejauh ini contoh-contohnya mengisi member di dalam isi constructor. Cara itu berfungsi untuk tipe sederhana, tetapi bukan alat yang tepat. Saat isi constructor berjalan, setiap member sudah dibuat dengan nilai default; isi constructor lalu membuang nilai itu dan menimpanya. Member initializer list menginisialisasi setiap member secara langsung, sebelum isi constructor, dalam satu langkah.

Sintaksnya berupa titik dua setelah daftar parameter, lalu pasangan member(value):

Untuk member string, cara ini juga menghindari pembuatan string kosong yang lalu ditimpa: initializer list langsung membangunnya dengan benar sejak awal.

Initializer list bukan sekadar optimasi; ia wajib dalam tiga kasus, karena isi constructor hanya bisa mengisi nilai, bukan menginisialisasi:

  • Member const: kamu tidak bisa mengisi const setelah ia ada.
  • Member referensi: referensi harus diikat saat ia dibuat.
  • Member yang tipenya tidak punya default constructor.
class Sensor {
    const int id;        // const member
    int& slot;           // reference member

public:
    Sensor(int sensorId, int& s) : id(sensorId), slot(s) {}
    // Trying to set id or slot in the body would not compile.
};

Satu detail halus yang perlu kamu tahu: member diinisialisasi sesuai urutan deklarasi-nya di class, bukan urutan kamu menuliskannya di initializer list. Kalau initializer satu member membaca member lain, urutan deklarasilah yang menentukan. Ketidakcocokan keduanya adalah sumber klasik pemakaian nilai yang belum diinisialisasi.

Argumen Default dan Delegating Constructor

Kamu tidak selalu butuh overload terpisah. Argumen default membuat satu constructor bisa menangani beberapa kasus: hilangkan sebuah argumen dan nilai default akan mengisinya:

Hati-hati menggabungkan parameterized constructor yang punya nilai default dengan default constructor Point() yang terpisah. Compiler tidak bisa menentukan mana yang harus dipanggil untuk Point p; dan akan melaporkan ambiguitas. Pilih salah satu cara saja.

Kalau kamu memang punya beberapa constructor dengan langkah persiapan yang sama, delegating constructor (C++11) membuat satu constructor bisa memanggil constructor lain alih-alih mengulang logikanya. Kamu "mendelegasikan" dengan menaruh constructor lain itu di initializer list:

Copy Constructor

Saat kamu membuat objek sebagai salinan objek lain, misalnya dengan meneruskannya by value, mengembalikannya, atau menulis Foo b = a;, yang berjalan adalah copy constructor. Signature-nya menerima referensi const ke tipe yang sama:

ClassName(const ClassName& other);

Kalau kamu tidak menulisnya, compiler membuatkan copy constructor default yang menyalin setiap member. Untuk class yang hanya berisi nilai (int, string, vector), itu sudah tepat dan kamu sebaiknya tidak menulis versimu sendiri.

Jebakan besarnya ada di bab berikutnya tentang memori: kalau class-mu memiliki raw pointer ke memori heap, copy constructor default menyalin pointer-nya, bukan datanya. Akibatnya dua objek menunjuk ke memori yang sama, dan keduanya akan mencoba membebaskannya. Itulah bug double-free. Patokannya adalah Rule of Three/Five: kalau kamu menulis destructor sendiri, hampir pasti kamu juga butuh copy constructor (dan copy assignment) sendiri. Di C++ modern, solusi yang lebih rapi adalah menyimpan std::vector atau smart pointer supaya copy yang dibuat compiler langsung berfungsi.

Perhatikan juga bahwa menerima parameter by reference itu wajib, bukan pilihan: copy constructor yang menerima argumennya by value harus menyalin argumen itu untuk memanggil dirinya sendiri. Hasilnya rekursi tanpa akhir yang bahkan tidak akan bisa dikompilasi.

Berikutnya: Destructor

Constructor menyiapkan objek; destructor membongkarnya. Saat objek keluar dari scope atau di-delete, destructor-nya berjalan otomatis. Ini tempat yang tepat untuk melepaskan file, koneksi jaringan, atau memori heap yang dipegang objek itu. Halaman berikutnya membahas cara kerja destructor, kapan tepatnya ia berjalan, dan bagaimana ia berpasangan dengan constructor untuk membentuk pola RAII yang andal di C++.

Pertanyaan yang sering diajukan

Apa itu constructor di C++?

Constructor adalah member function khusus yang namanya sama dengan nama class dan tidak punya tipe kembalian. Ia berjalan otomatis saat objek dibuat, dan tugasnya adalah membawa objek ke keadaan yang valid dan terinisialisasi penuh sebelum kode lain memakainya.

Apa perbedaan default constructor dan parameterized constructor?

Default constructor tidak menerima argumen dan dipakai saat kamu membuat objek tanpa memberikan nilai (Point p;). Parameterized constructor menerima argumen sehingga pemanggil bisa menginisialisasi objek dengan nilai tertentu (Point p(3, 4);). Sebuah class bisa punya keduanya karena constructor di-overload berdasarkan daftar parameternya.

Kenapa sebaiknya memakai member initializer list di C++?

Member initializer list (: name(n), age(a)) menginisialisasi member secara langsung, sebelum isi constructor dijalankan. List ini wajib untuk member const, referensi, dan member yang tidak punya default constructor, dan ia menghindari pemborosan berupa membuat nilai default lalu menimpanya, yang terjadi kalau kamu mengisi member di dalam isi constructor.

Ilustrasi bahasa pemrograman di Coddy

Belajar coding dengan Coddy

Mulai