Semua data member yang kita tulis selama ini berlaku pola yang sama: setiap object mendapat salinannya sendiri. Padahal ada data yang secara logika bukan milik satu object — jumlah total object yang pernah dibuat, konstanta konversi yang sama untuk semua, atau konfigurasi global class. Untuk kebutuhan itu, C++ menyediakan static members: data member dan member function yang melekat pada class, bukan pada object. Chapter ini membahas cara mendeklarasikannya, dua cara mendefinisikan data statik, dan penggunaan klasiknya: penghitung instans.
Member static: Milik Class, Bukan Milik Object #
Data member yang diberi kata kunci static disimpan sebagai satu salinan tunggal yang dibagi oleh semua object class tersebut. Membuat sepuluh object tidak membuat sepuluh salinan member static — ada satu, dan semua object melihat nilai yang sama ketika mengubahnya. Konsekuensinya menarik: member static ada bahkan sebelum object pertama dibuat, dan tetap ada setelah semua object berakhir.
Karena milik class, akses paling jujur ke member static public juga memakai nama class, bukan nama object: Motor::ambilJumlah() alih-alih motor1.ambilJumlah(). Bentuk kedua secara teknis sah (compiler menghubungkannya ke member yang sama), tetapi menulis lewat nama class menyampaikan maksud dengan benar: nilai ini tidak terikat pada object tertentu. Member static pun tetap tunduk pada access specifiers — member static private hanya bisa disentuh dari dalam class, dan bila perlu dibaca dari luar, sediakan static member function public sebagai jalurnya.
Mendefinisikan Static Data Member #
Member static tidak ikut tersalin ke object, sehingga tidak bisa “dibuat” bersama object. Ada dua cara mendefinisikannya. Cara klasik: deklarasikan di dalam class dengan static int jumlah;, lalu definisikan di luar class satu kali saja — int Sepeda::jumlah = 0; — biasanya di bawah definisi class, tanpa kata static lagi. Cara modern sejak C++17: tambahkan kata kunci inline — static inline int jumlah = 0; — dan definisi langsung tertanam di dalam class, tanpa baris di luar.
Perbedaan praktisnya terasa saat kode dipecah ke banyak file: definisi klasik harus berada di satu file .cpp saja (menaruhnya di header memicu error duplikasi), sedangkan inline static aman ditulis di header karena inline mengizinkan beberapa definisi identik yang digabung linker menjadi satu. Untuk latihan satu file, keduanya bekerja sama baik; memakai keduanya sekaligus dalam satu contoh — seperti yang akan kita lakukan — membuat perbedaannya terlihat jelas.
Static Member Function: Tanpa this #
Member function juga bisa dibuat static dengan kata kunci static di depan deklarasinya. Perbedaan fundamentalnya: static member function tidak menerima pointer this — ia tidak terikat pada object pemanggil mana pun. Akibat logisnya: di dalam static member function tidak ada akses ke data member non-static, karena tanpa this tidak ada object yang member-nya bisa dimaksud. Ia hanya boleh menyentuh member static dan hal-hal di luar class yang tidak membutuhkan object.
Karena tidak punya this, static member function bisa dipanggil lewat nama class bahkan saat tidak ada satu object pun: Motor::ambilJumlah(). Inilah pola yang tepat untuk fungsi utilitas yang berkaitan dengan class tetapi tidak butuh state object — getter penghitung instans, konversi satuan milik domain, atau pabrik object sederhana. Bila suatu saat Anda menulis member function yang tidak menyentuh member non-static sama sekali, pertimbangkan menjadikannya static agar niatnya eksplisit.
Contoh: Penghitung Instans #
Program berikut memakai dua class: Motor dengan inline static (C++17) yang juga mengurangi hitungan lewat destructor, dan Sepeda dengan pola klasik definisi di luar class:
#include <iostream>
#include <string>
// Cara modern (C++17): inline static, definisi langsung di dalam class
class Motor {
private:
std::string plat;
static inline int jumlah = 0; // dibagi semua object Motor
public:
Motor(const std::string& p) : plat(p) {
++jumlah; // setiap object baru menambah hitungan
}
~Motor() {
--jumlah;
}
// Static member function: tidak punya this, hanya menyentuh member static
static int ambilJumlah() {
return jumlah;
}
void cetak() {
std::cout << "Motor " << plat << " aktif\n";
}
};
// Cara klasik: hanya deklarasi di dalam class, definisi di luar
class Sepeda {
private:
static int jumlah; // deklarasi saja
public:
Sepeda() {
++jumlah;
}
static int ambilJumlah() {
return jumlah;
}
};
// Definisi wajib di luar class, tepat satu kali di seluruh program
int Sepeda::jumlah = 0;
int main() {
std::cout << "Motor aktif: " << Motor::ambilJumlah() << "\n";
Motor m1("B 1234 CD");
Motor m2("D 5678 EF");
std::cout << "Motor aktif: " << Motor::ambilJumlah() << "\n";
m1.cetak();
Sepeda s1;
Sepeda s2;
Sepeda s3;
std::cout << "Sepeda: " << Sepeda::ambilJumlah() << "\n";
return 0;
}Output yang Dihasilkan:
Motor aktif: 0
Motor aktif: 2
Motor B 1234 CD aktif
Sepeda: 3Bedah baris demi baris:
- Baris 8 (
static inline int jumlah = 0;): member static dengan definisi langsung di dalam class (C++17). Satu salinan tunggal untuk semua objectMotor, siap dipakai bahkan saat belum ada object. - Baris 13-16 dan 18-21 (constructor dan destructor): constructor menambah hitungan, destructor menguranginya — pasangan yang menjaga angka tetap berarti “jumlah object yang sedang hidup”. Ini bukti nyata kerja sama constructor-destructor dari chapter sebelumnya.
- Baris 24-27 (
static int ambilJumlah()): static member function tanpathis. Ia hanya membacajumlah; menyentuhplatdi sini akan langsung ditolak compiler. - Baris 43-44 dan 62-63 (
Sepedaklasik): deklarasistatic int jumlah;di dalam class disertai definisiint Sepeda::jumlah = 0;di luar class — catatan: tanpa katastaticpada definisinya. Pola inilah yang ditemui di kode pra-C++17. - Baris 66 (cetak pertama):
Motor aktif: 0dicetak sebelum object pertama dibuat — bukti member static hidup di level class, bukan di dalam object. Setelahm1danm2, angkanya naik menjadi2, danSepedamenghitung3object dari tiga constructor.
Member static memperluas kemampuan class ke luar dirinya, tetapi tetap tunduk pada tembok private. Ada satu mekanisme terakhir yang justru dirancang untuk menembus tembok itu secara terkendali: friend, yang kita bahas pada Chapter penutup bagian ini.
Rujukan resmi: Static members (cppreference) , Classes (cppreference) .