Menu
CoddyTech

Casting Dinamis & RTTI

Termasuk bagian Pemrograman Berorientasi Object dalam perjalanan C++ di Coddy. Pelajaran 62 dari 104.

Terkadang, saat bekerja dengan polimorfisme, kamu perlu menentukan tipe sebenarnya dari sebuah object saat program berjalan atau mengonversi pointer class dasar ke pointer class turunan dengan aman. C++ menyediakan RTTI (Runtime Type Information) dan dynamic_cast untuk situasi ini.

dynamic_cast mengonversi pointer atau referensi dalam hierarki pewarisan dengan aman. Berbeda dengan static_cast, fitur ini melakukan pemeriksaan saat runtime dan mengembalikan nullptr jika konversi tidak valid:

class Animal {
public:
    virtual ~Animal() = default;
};

class Dog : public Animal {
public:
    void bark() { std::cout << "Woof!" << std::endl; }
};

class Cat : public Animal {};

Animal* animal = new Dog();
Dog* dog = dynamic_cast<Dog*>(animal);  // Berhasil: mengembalikan pointer yang valid

if (dog) {
    dog->bark();  // Kamu dapat memanggil method khusus Dog dengan aman
}

Cat* cat = dynamic_cast<Cat*>(animal);  // Gagal: mengembalikan nullptr

Penting: dynamic_cast hanya berfungsi dengan tipe polimorfik (class yang memiliki setidaknya satu fungsi virtual). Operator typeid memungkinkan kamu memeriksa tipe sebenarnya dari sebuah object:

#include <typeinfo>

Animal* pet = new Dog();
std::cout << typeid(*pet).name() << std::endl;  // Menampilkan informasi tipe untuk Dog

Meskipun dynamic_cast berguna, penggunaan yang terlalu sering biasanya menunjukkan masalah desain. Sebisa mungkin, gunakan fungsi virtual karena cara ini memungkinkan object menangani perilaku khusus tipe tanpa pemeriksaan tipe secara eksplisit.

challenge icon

Tantangan

Mudah

Mari buat sistem inspeksi kendaraan yang menggunakan dynamic_cast untuk mengidentifikasi dan berinteraksi dengan berbagai jenis kendaraan secara aman. Kamu akan membuat hierarki kendaraan tempat seorang pemeriksa perlu melakukan pemeriksaan khusus tipe yang hanya didukung oleh kendaraan tertentu.

Kamu akan mengatur kodemu dalam tiga file:

  • Vehicle.h: Definisikan class dasar Vehicle yang mewakili kendaraan apa pun di dalam sistem:
    • Anggota std::string licensePlate yang dilindungi
    • Konstruktor yang menginisialisasi nomor pelat
    • Method virtual getDescription() yang mengembalikan "Vehicle: <licensePlate>"
    • Destruktor virtual
  • Vehicles.h: Definisikan tiga jenis kendaraan turunan:

    Car:

    • Anggota int seatCount yang bersifat private
    • Konstruktor yang menerima nomor pelat dan jumlah kursi
    • Timpa getDescription() agar mengembalikan "Car: <licensePlate>"
    • Method inspectSeatbelts() yang mencetak: Inspecting <seatCount> seatbelts in <licensePlate>

    Truck:

    • Anggota double cargoCapacity yang bersifat private (dalam ton)
    • Konstruktor yang menerima nomor pelat dan kapasitas kargo
    • Timpa getDescription() agar mengembalikan "Truck: <licensePlate>"
    • Method inspectCargo() yang mencetak: Inspecting cargo area (<cargoCapacity> tons) in <licensePlate>

    Motorcycle:

    • Anggota bool hasSidecar yang bersifat private
    • Konstruktor yang menerima nomor pelat dan status sespan
    • Timpa getDescription() agar mengembalikan "Motorcycle: <licensePlate>"
    • Method inspectHelmetStorage() yang mencetak: Inspecting helmet storage in <licensePlate> jika kendaraan memiliki sespan, atau No helmet storage in <licensePlate> jika tidak
  • main.cpp: Baca tiga input (masing-masing pada baris terpisah):
    1. Nomor pelat Car
    2. Nomor pelat Truck
    3. Nomor pelat Motorcycle

    Buat Car dengan 4 kursi, Truck dengan kapasitas 10.5 ton, dan Motorcycle dengan sespan. Simpan ketiganya dalam sebuah array berisi pointer Vehicle*.

    Telusuri array dan lakukan hal berikut untuk setiap kendaraan:

    1. Cetak deskripsinya menggunakan getDescription()
    2. Gunakan dynamic_cast untuk mencoba melakukan cast ke setiap jenis turunan
    3. Jika cast ke Car* berhasil, panggil inspectSeatbelts()
    4. Jika cast ke Truck* berhasil, panggil inspectCargo()
    5. Jika cast ke Motorcycle* berhasil, panggil inspectHelmetStorage()

    Cetak satu baris kosong di antara pemeriksaan setiap kendaraan. Setelah selesai, bersihkan object yang dialokasikan secara dinamis.

Contohnya, dengan input ABC-123, TRK-456, dan MTR-789:

Car: ABC-123
Inspecting 4 seatbelts in ABC-123

Truck: TRK-456
Inspecting cargo area (10.5 tons) in TRK-456

Motorcycle: MTR-789
Inspecting helmet storage in MTR-789

Perhatikan bahwa dynamic_cast mengembalikan pointer yang valid hanya ketika tipe object sebenarnya cocok dengan tipe target. Untuk setiap kendaraan, hanya satu dari tiga cast yang akan berhasil, sehingga kamu dapat memanggil method pemeriksaan khusus tipe dengan aman. Inilah keunggulan RTTI: menentukan tipe sebenarnya saat program berjalan dan bertindak sesuai dengan tipe tersebut.

Coba sendiri

#include <iostream>
#include <string>
#include "Vehicle.h"
#include "Vehicles.h"

using namespace std;

int main() {
    // Baca input
    string carPlate, truckPlate, motorcyclePlate;
    cin >> carPlate;
    cin >> truckPlate;
    cin >> motorcyclePlate;

    // TODO: Buat Car dengan 4 kursi
    // TODO: Buat Truck dengan kapasitas 10.5 ton
    // TODO: Buat Motorcycle dengan sespan (true)

    // TODO: Simpan ketiganya dalam array pointer Vehicle*

    // TODO: Lakukan perulangan pada array dan untuk setiap kendaraan:
    //   1. Cetak deskripsinya menggunakan getDescription()
    //   2. Gunakan dynamic_cast untuk mencoba mengonversi ke setiap tipe turunan
    //   3. Jika konversi ke Car* berhasil, panggil inspectSeatbelts()
    //   4. Jika konversi ke Truck* berhasil, panggil inspectCargo()
    //   5. Jika konversi ke Motorcycle* berhasil, panggil inspectHelmetStorage()
    //   6. Cetak satu baris kosong di antara pemeriksaan setiap kendaraan

    // TODO: Hapus object yang dialokasikan secara dinamis

    return 0;
}
quiz iconUji dirimu

Pelajaran ini berisi kuis singkat. Mulai pelajarannya untuk menjawab kuis dan melacak progresmu.

Semua pelajaran di Pemrograman Berorientasi Object

Latihan sendiri: Compiler C++ online