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 nullptrPenting: 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 DogMeskipun 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.
Tantangan
MudahMari 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 dasarVehicleyang mewakili kendaraan apa pun di dalam sistem:- Anggota
std::string licensePlateyang dilindungi - Konstruktor yang menginisialisasi nomor pelat
- Method virtual
getDescription()yang mengembalikan"Vehicle: <licensePlate>" - Destruktor virtual
- Anggota
Vehicles.h: Definisikan tiga jenis kendaraan turunan:Car:- Anggota
int seatCountyang 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 cargoCapacityyang 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 hasSidecaryang 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, atauNo helmet storage in <licensePlate>jika tidak
- Anggota
main.cpp: Baca tiga input (masing-masing pada baris terpisah):- Nomor pelat Car
- Nomor pelat Truck
- Nomor pelat Motorcycle
Buat
Cardengan 4 kursi,Truckdengan kapasitas 10.5 ton, danMotorcycledengan sespan. Simpan ketiganya dalam sebuah array berisi pointerVehicle*.Telusuri array dan lakukan hal berikut untuk setiap kendaraan:
- Cetak deskripsinya menggunakan
getDescription() - Gunakan
dynamic_castuntuk mencoba melakukan cast ke setiap jenis turunan - Jika cast ke
Car*berhasil, panggilinspectSeatbelts() - Jika cast ke
Truck*berhasil, panggilinspectCargo() - Jika cast ke
Motorcycle*berhasil, panggilinspectHelmetStorage()
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-789Perhatikan 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;
}
Pelajaran ini berisi kuis singkat. Mulai pelajarannya untuk menjawab kuis dan melacak progresmu.
Semua pelajaran di Pemrograman Berorientasi Object
1Dasar-Dasar OOP
File EksternalBuild dan Kompilasi C++File Header dan File SourceNamespace dan CakupanPengantar OOP dalam C++class vs objectPointer 'this'method (Fungsi Anggota)Atribut (Anggota Data)Dasar Ctor dan DtorRingkasan: Kalkulator Sederhana4Properti class
Anggota instance vs staticGetter dan setterFungsi anggota constKata kunci mutableMethod dan variabel staticFungsi dan class friendRangkuman, Pengelola Rekening Bank7Pewarisan
Pewarisan DasarTingkat Akses pada PewarisanUrutan Pemanggilan Ctor & DtorPenimpaan methodFungsi Virtual & VTablePewarisan BergandaPewarisan VirtualRangkuman: Hierarki Karyawan2Manajemen Memori
Memori Stack vs HeapPointer dan ReferenceMemori Dinamis (new/delete)Smart Pointer di C++RAII di C++Rangkuman: Pengelola Array Dinamis5Enkapsulasi
Penentu Akses dalam C++Penentu Akses secara MendalamPenyembunyian Informasistruct vs classNested dan Inner classRangkuman, Sistem Catatan Siswa8Polimorfisme
Polimorfisme saat Compile vs RuntimeOverloading FungsiMeninjau Kembali Fungsi VirtualFungsi Virtual MurniKelas AbstrakDesain Interface di C++Casting Dinamis & RTTIRangkuman: Kalkulator Bentuk3Konstruktor & Destruktor
Konstruktor DefaultKonstruktor BerparameterKonstruktor SalinKonstruktor PindahDaftar Inisialisasi KonstruktorKonstruktor DelegasiKupas Tuntas DestruktorAturan Tiga, Lima, dan NolRangkuman: class String6Overloading Operator
Pengantar Overloading OperatorOverloading Operator AritmetikaOverloading Operator PerbandinganOperator StreamOverloading Operator PenugasanOverloading Operator [] dan ()Operator Konversi TipeRingkasan, class Matrix9Template
Template FungsiTemplate classSpesialisasi TemplateTemplate VariadikDasar SFINAE & Type TraitsRangkuman, Container GenerikLatihan sendiri: Compiler C++ online