Langsung ke konten
KamusNgoding
Menengah Cpp 3 menit baca

Class dan Object di C++: Dasar OOP

#cpp #class #object #oop #constructor #destructor #encapsulation #this

Sejauh ini kita menulis kode secara prosedural — serangkaian fungsi dan variabel terpisah. Object-Oriented Programming (OOP) mengubah cara berpikir ini: kita mengelompokkan data (atribut) dan perilaku (method) menjadi satu kesatuan yang disebut class. Bayangkan membangun sistem manajemen karyawan — alih-alih variabel terpisah nama_karyawan, gaji, jabatan, kita buat class Karyawan yang merangkum semuanya. Di artikel ini kita mempelajari dasar OOP di C++.

Struct vs Class

C++ memiliki dua cara mengelompokkan data: struct dan class. Perbedaan utamanya hanya pada default akses:

struct TitikStruct {
    int x, y; // default: public
};

class TitikClass {
    int x, y; // default: private — tidak bisa diakses dari luar!
};

TitikStruct s; s.x = 10; // ✅ Valid
TitikClass c;  c.x = 10; // ❌ Error: 'x' is private

Konvensi: Gunakan struct untuk data sederhana tanpa perilaku; gunakan class untuk objek dengan atribut dan method.

Membuat Class Pertama

#include <iostream>
#include <string>
using namespace std;

class BukuTabungan {
private:
    string pemilik;    // Atribut private — tidak bisa diakses langsung dari luar
    double saldo;

public:
    // Constructor: dipanggil saat objek dibuat
    BukuTabungan(string nama, double saldo_awal) {
        pemilik = nama;
        saldo = saldo_awal;
    }

    // Method public — antarmuka untuk berinteraksi dengan objek
    void setor(double jumlah) {
        if (jumlah > 0) {
            saldo += jumlah;
            cout << "Setor Rp " << jumlah << " — Saldo baru: " << saldo << endl;
        }
    }

    void tarik(double jumlah) {
        if (jumlah > saldo) {
            cout << "Saldo tidak cukup!" << endl;
            return;
        }
        saldo -= jumlah;
        cout << "Tarik Rp " << jumlah << " — Saldo baru: " << saldo << endl;
    }

    void info() const { // const: method ini tidak mengubah atribut
        cout << "Pemilik: " << pemilik << " | Saldo: Rp " << saldo << endl;
    }
};

int main() {
    BukuTabungan tabungan("Rina Sari", 1_000_000);
    tabungan.info();
    // Output: Pemilik: Rina Sari | Saldo: Rp 1000000

    tabungan.setor(500_000);
    // Output: Setor Rp 500000 — Saldo baru: 1500000

    tabungan.tarik(200_000);
    // Output: Tarik Rp 200000 — Saldo baru: 1300000

    tabungan.tarik(2_000_000);
    // Output: Saldo tidak cukup!

    // tabungan.saldo = 999999; // ❌ Error: 'saldo' is private
    return 0;
}

Access Specifiers

class Contoh {
public:
    int publik;      // Bisa diakses dari mana saja

protected:
    int terlindungi; // Bisa diakses dari class ini dan class turunannya

private:
    int privat;      // Hanya bisa diakses dari dalam class ini
};

Constructor

Constructor adalah method khusus yang dipanggil saat objek dibuat — namanya sama dengan class dan tidak memiliki return type.

class Mahasiswa {
public:
    string nama;
    int nim;
    double ipk;

    // Default constructor
    Mahasiswa() {
        nama = "Tidak Diketahui";
        nim = 0;
        ipk = 0.0;
    }

    // Parameterized constructor
    Mahasiswa(string n, int i, double nilai_ipk) {
        nama = n;
        nim = i;
        ipk = nilai_ipk;
    }

    // Constructor dengan initializer list (cara yang lebih efisien)
    // Mahasiswa(string n, int i, double ipk_val) : nama(n), nim(i), ipk(ipk_val) {}

    void tampilkan() const {
        cout << "[" << nim << "] " << nama << " — IPK: " << ipk << endl;
    }
};

int main() {
    Mahasiswa m1;                          // Default constructor
    Mahasiswa m2("Ali Akbar", 2024001, 3.75); // Parameterized

    m1.tampilkan(); // Output: [0] Tidak Diketahui — IPK: 0
    m2.tampilkan(); // Output: [2024001] Ali Akbar — IPK: 3.75

    return 0;
}

Destructor

Destructor dipanggil otomatis saat objek dihapus dari memori — berguna untuk membersihkan resource:

class KoneksiDatabase {
private:
    string host;
    bool terhubung;

public:
    KoneksiDatabase(string h) : host(h), terhubung(false) {
        cout << "Membuka koneksi ke " << host << endl;
        terhubung = true;
    }

    ~KoneksiDatabase() { // Destructor: nama sama dengan class, diawali ~
        if (terhubung) {
            cout << "Menutup koneksi ke " << host << endl;
            terhubung = false;
        }
    }

    void query(string sql) const {
        if (terhubung)
            cout << "Menjalankan: " << sql << endl;
    }
};

int main() {
    {
        KoneksiDatabase db("localhost:5432");
        db.query("SELECT * FROM users");
    } // ← Destructor otomatis dipanggil saat keluar dari scope ini

    cout << "Program selesai" << endl;
    return 0;
}
// Output:
// Membuka koneksi ke localhost:5432
// Menjalankan: SELECT * FROM users
// Menutup koneksi ke localhost:5432
// Program selesai

Pola ini disebut RAII (Resource Acquisition Is Initialization) — salah satu pola terpenting di C++.

Pointer this

this adalah pointer ke objek saat ini — berguna saat nama parameter sama dengan nama atribut:

class Produk {
private:
    string nama;
    double harga;

public:
    Produk(string nama, double harga) {
        this->nama = nama;    // this->nama = atribut, nama = parameter
        this->harga = harga;
    }

    // Method chaining dengan this
    Produk& set_nama(string nama) {
        this->nama = nama;
        return *this; // Mengembalikan objek itu sendiri
    }

    Produk& set_harga(double harga) {
        this->harga = harga;
        return *this;
    }

    void info() const {
        cout << nama << " — Rp " << harga << endl;
    }
};

int main() {
    Produk p("Laptop", 0);

    // Method chaining
    p.set_nama("ThinkPad X1").set_harga(15_000_000);
    p.info();
    // Output: ThinkPad X1 — Rp 15000000

    return 0;
}

Getter dan Setter

Untuk atribut private, buat method getter/setter:

class Suhu {
private:
    double celsius;

public:
    Suhu(double c = 0) : celsius(c) {}

    // Getter
    double get_celsius() const { return celsius; }
    double get_fahrenheit() const { return celsius * 9.0/5.0 + 32; }
    double get_kelvin() const { return celsius + 273.15; }

    // Setter dengan validasi
    void set_celsius(double c) {
        if (c < -273.15) {
            cout << "Suhu tidak bisa di bawah nol mutlak!" << endl;
            return;
        }
        celsius = c;
    }
};

int main() {
    Suhu s(100);
    cout << s.get_celsius()    << "°C" << endl; // Output: 100°C
    cout << s.get_fahrenheit() << "°F" << endl; // Output: 212°F
    cout << s.get_kelvin()     << "K"  << endl; // Output: 373.15K

    s.set_celsius(-300); // Output: Suhu tidak bisa di bawah nol mutlak!
    return 0;
}

Pertanyaan yang Sering Diajukan

Apa perbedaan utama struct dan class di C++?

Satu-satunya perbedaan teknis adalah akses default: struct defaultnya public, class defaultnya private. Secara konvensi, struct digunakan untuk Plain Old Data (POD) — kumpulan data sederhana tanpa method kompleks. class digunakan untuk objek dengan perilaku (method), invariants, dan enkapsulasi. Tidak ada keharusan teknis, tapi mengikuti konvensi membuat kode lebih mudah dipahami.

Apa itu RAII dan mengapa penting di C++?

RAII (Resource Acquisition Is Initialization) adalah pola di mana resource (memori, koneksi, file) diperoleh di constructor dan dibebaskan di destructor. Ini menjamin resource selalu dibersihkan meski ada exception. C++ modern sangat mengandalkan RAII melalui smart pointer (unique_ptr, shared_ptr) dan kelas seperti ifstream yang otomatis menutup file saat keluar scope.

Kapan harus membuat method const?

Tandai method dengan const jika method tidak mengubah state objek (tidak mengubah atribut). Ini penting karena: (1) memungkinkan method dipanggil pada objek const, (2) compiler bisa mengoptimalkan, dan (3) menjadi dokumentasi bahwa method ini “read-only”. Sebagai praktik baik, tandai semua getter dan method informasi dengan const.

Apa keuntungan menggunakan initializer list di constructor?

Initializer list (: nama(n), nim(i)) menginisialisasi atribut langsung, lebih efisien daripada assignment di dalam constructor body. Untuk atribut yang merupakan objek (bukan primitif), initializer list memanggil copy constructor langsung — lebih cepat daripada konstruksi default lalu assignment. Untuk atribut const dan reference, initializer list adalah wajib.

Kesimpulan

KonsepSintaksKeterangan
Classclass NamaClass { ... };Blueprint objek
Privateprivate:Hanya bisa diakses dalam class
ConstructorClass(params) { ... }Dipanggil saat objek dibuat
Destructor~Class() { ... }Dipanggil saat objek dihapus
this pointerthis->atributReferensi ke objek saat ini
const methodvoid f() constTidak mengubah atribut

Artikel sebelumnya: Array dan Vector di C++ — mengelola kumpulan data.

Langkah selanjutnya: Inheritance dan Polymorphism di C++ — cara membuat hierarki class dan polimorfisme di C++.

Artikel Terkait