Menu
Coddy logo textTech

Dynamic Casting ve RTTI

Coddy'nin C++ Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası. Ders 62 / 104.

Bazen polimorfizm ile çalışırken bir nesnenin çalışma zamanındaki gerçek türünü belirlemeniz veya bir temel sınıf işaretçisini türetilmiş sınıf işaretçisine güvenli bir şekilde dönüştürmeniz gerekir. C++ bu durumlar için RTTI (Çalışma Zamanı Tür Bilgisi) ve dynamic_cast sağlar.

dynamic_cast, bir kalıtım hiyerarşisi içindeki işaretçileri veya referansları güvenli bir şekilde dönüştürür. static_cast'ten farklı olarak çalışma zamanında bir kontrol gerçekleştirir ve dönüşüm geçersizse nullptr döndürür:

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);  // Başarılı: geçerli işaretçi döndürür

if (dog) {
    dog->bark();  // Dog'a özgü metodu çağırmak güvenli
}

Cat* cat = dynamic_cast<Cat*>(animal);  // Başarısız: nullptr döndürür

Önemli: dynamic_cast yalnızca polimorfik türlerle (en az bir sanal işlevi olan sınıflarla) çalışır. typeid işleci, bir nesnenin gerçek türünü sorgulamanıza olanak tanır:

#include <typeinfo>

Animal* pet = new Dog();
std::cout << typeid(*pet).name() << std::endl;  // Dog için tip bilgisini yazdırır

dynamic_cast kullanışlı olsa da sık kullanımı genellikle bir tasarım sorununa işaret eder. Mümkün olduğunda sanal işlevleri tercih et; çünkü bunlar, açık tür denetimi olmadan nesnenin türe özgü davranışı ele almasını sağlar.

challenge icon

Görev

Kolay

Farklı araç türlerini güvenli bir şekilde tanımlamak ve bunlarla etkileşim kurmak için dynamic_cast kullanan bir araç denetim sistemi oluşturalım. Belirli araçların desteklediği türe özgü kontrolleri bir denetçinin gerçekleştirmesi gereken bir araç hiyerarşisi oluşturacaksınız.

Kodunuzu üç dosyada düzenleyeceksiniz:

  • Vehicle.h: Sistemdeki herhangi bir aracı temsil eden bir temel Vehicle sınıfı tanımlayın:
    • Korunan bir std::string licensePlate üyesi
    • Plaka numarasını başlatan bir oluşturucu
    • getDescription() döndüren sanal bir "Vehicle: <licensePlate>" yöntemi
    • Sanal bir yok edici
  • Vehicles.h: Türetilmiş üç araç türü tanımlayın:

    Car:

    • Özel bir int seatCount üyesi
    • Plaka numarasını ve koltuk sayısını alan bir oluşturucu
    • getDescription() döndürecek şekilde "Car: <licensePlate>" yöntemini geçersiz kılma
    • inspectSeatbelts() yazdıran bir Inspecting <seatCount> seatbelts in <licensePlate> yöntemi

    Truck:

    • Özel bir double cargoCapacity üyesi (ton cinsinden)
    • Plaka numarasını ve yük kapasitesini alan bir oluşturucu
    • getDescription() döndürecek şekilde "Truck: <licensePlate>" yöntemini geçersiz kılma
    • inspectCargo() yazdıran bir Inspecting cargo area (<cargoCapacity> tons) in <licensePlate> yöntemi

    Motorcycle:

    • Özel bir bool hasSidecar üyesi
    • Plaka numarasını ve sepet durumunu alan bir oluşturucu
    • getDescription() döndürecek şekilde "Motorcycle: <licensePlate>" yöntemini geçersiz kılma
    • Sepeti varsa inspectHelmetStorage(), yoksa Inspecting helmet storage in <licensePlate> yazdıran bir No helmet storage in <licensePlate> yöntemi
  • main.cpp: Üç girdi okuyun (her biri ayrı bir satırda):
    1. Car plaka numarası
    2. Truck plaka numarası
    3. Motorcycle plaka numarası

    4 koltuklu bir Car, 10.5 ton kapasiteli bir Truck ve sepetli bir Motorcycle oluşturun. Üçünü de Vehicle* işaretçilerinden oluşan bir dizide saklayın.

    Dizi üzerinde döngü kurun ve her araç için:

    1. getDescription() kullanarak açıklamasını yazdırın
    2. Türetilmiş her türe dönüştürmeyi denemek için dynamic_cast kullanın
    3. Car* türüne dönüştürme başarılı olursa inspectSeatbelts() çağrısını yapın
    4. Truck* türüne dönüştürme başarılı olursa inspectCargo() çağrısını yapın
    5. Motorcycle* türüne dönüştürme başarılı olursa inspectHelmetStorage() çağrısını yapın

    Her aracın denetimi arasında boş bir satır yazdırın. İşiniz bittiğinde dinamik olarak ayrılmış nesneleri temizleyin.

Örneğin, girdiler ABC-123, TRK-456 ve MTR-789 olduğunda:

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

dynamic_cast işleminin yalnızca gerçek nesne türü hedef türle eşleştiğinde geçerli bir işaretçi döndürdüğüne dikkat edin. Her araç için üç dönüştürmeden yalnızca biri başarılı olur; bu da türe özgü denetim yöntemini güvenli bir şekilde çağırmanızı sağlar. RTTI'ın gücü budur: çalışma zamanında gerçek türü belirlemek ve buna göre hareket etmek.

Kendin dene

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

using namespace std;

int main() {
    // Girdileri oku
    string carPlate, truckPlate, motorcyclePlate;
    cin >> carPlate;
    cin >> truckPlate;
    cin >> motorcyclePlate;

    // TODO: 4 koltuklu bir Car oluştur
    // TODO: 10.5 ton kapasiteli bir Truck oluştur
    // TODO: Yan sepetli (true) bir Motorcycle oluştur

    // TODO: Üçünü de Vehicle* işaretçilerinden oluşan bir dizide sakla

    // TODO: Diziyi döngüyle gez ve her araç için:
    //   1. getDescription() kullanarak açıklamasını yazdır
    //   2. Her türetilmiş türe dönüştürmeyi denemek için dynamic_cast kullan
    //   3. Car*'a dönüştürme başarılı olursa, inspectSeatbelts() çağır
    //   4. Truck*'a dönüştürme başarılı olursa, inspectCargo() çağır
    //   5. If cast to Motorcycle* succeeds, call inspectHelmetStorage()
    //   6. Her aracın incelemesi arasına boş bir satır yazdır

    // TODO: Dinamik olarak ayrılmış nesneleri temizle

    return 0;
}
quiz iconKendini test et

Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.

Nesne Yönelimli Programlama bölümündeki tüm dersler

Kendi başına pratik yap: Online C++ derleyicisi