dynamic_cast


Keyword: dynamic_cast

Introduction

dynamic_cast is one of the four casting operators in C++. It's primarily used for safe downcasting in inheritance hierarchies. Unlike static_cast, dynamic_cast performs runtime type checking, making it particularly useful in scenarios involving polymorphism.

Key Characteristics

Example 1: Basic Usage: Safe Downcasting

#include <iostream>

class Base {
public:
    virtual void print() { std::cout << "Base" << std::endl; }
    virtual ~Base() {}
};

class Derived : public Base {
public:
    void print() override { std::cout << "Derived" << std::endl; }
    void derivedMethod() { std::cout << "Derived method" << std::endl; }
};

int main() {
    Base* basePtr = new Derived();

    // Safe downcasting
    Derived* derivedPtr = dynamic_cast<Derived*>(basePtr);

    if (derivedPtr) {
        derivedPtr->derivedMethod();
    } else {
        std::cout << "Cast failed" << std::endl;
    }

    delete basePtr;
    return 0;
}

Explanation:

Example 2: Cross-Casting Between Sibling Classes

#include <iostream>

class Animal {
public:
    virtual void speak() = 0;
    virtual ~Animal() {}
};

class Flyable {
public:
    virtual void fly() = 0;
    virtual ~Flyable() {}
};

class Bird : public Animal, public Flyable {
public:
    void speak() override { std::cout << "Chirp" << std::endl; }
    void fly() override { std::cout << "Bird is flying" << std::endl; }
};

int main() {
    Bird* bird = new Bird();
    Animal* animal = bird;

    // Cross-casting from Animal* to Flyable*
    Flyable* flyable = dynamic_cast<Flyable*>(animal);

    if (flyable) {
        flyable->fly();
    } else {
        std::cout << "Cast failed" << std::endl;
    }

    delete bird;
    return 0;
}

Explanation:

Example 3: Using dynamic_cast with References

#include <iostream>
#include <stdexcept>

class Base {
public:
    virtual ~Base() {}
};

class Derived : public Base {
public:
    void derivedFunction() { std::cout << "Derived function" << std::endl; }
};

void processDerived(Base& base) {
    try {
        Derived& derived = dynamic_cast<Derived&>(base);
        derived.derivedFunction();
    } catch (const std::bad_cast& e) {
        std::cout << "Cast failed: " << e.what() << std::endl;
    }
}

int main() {
    Base baseObj;
    Derived derivedObj;

    processDerived(derivedObj);  // Succeeds
    processDerived(baseObj);     // Throws and catches std::bad_cast

    return 0;
}

Explanation:

Example 4: Runtime Type Identification (RTTI)

#include <iostream>
#include <vector>
#include <memory>

class Shape {
public:
    virtual void draw() = 0;
    virtual ~Shape() {}
};

class Circle : public Shape {
public:
    void draw() override { std::cout << "Drawing Circle" << std::endl; }
};

class Square : public Shape {
public:
    void draw() override { std::cout << "Drawing Square" << std::endl; }
};

int main() {
    std::vector<std::unique_ptr<Shape>> shapes;
    shapes.push_back(std::make_unique<Circle>());
    shapes.push_back(std::make_unique<Square>());
    shapes.push_back(std::make_unique<Circle>());

    for (const auto& shape : shapes) {
        shape->draw();

        if (dynamic_cast<Circle*>(shape.get())) {
            std::cout << "This is a Circle" << std::endl;
        } else if (dynamic_cast<Square*>(shape.get())) {
            std::cout << "This is a Square" << std::endl;
        }
    }

    return 0;
}

Explanation:

Additional Considerations

  1. Performance: dynamic_cast has a runtime cost due to type checking. Use it judiciously in performance-critical code.

  2. Design Implications: Frequent use of dynamic_cast might indicate a design that could benefit from refactoring.

  3. Compiler Support: Ensure that Runtime Type Information (RTTI) is enabled in your compiler settings.

  4. Smart Pointers: dynamic_cast works well with smart pointers, enhancing both safety and convenience.

Summary

dynamic_cast is a powerful tool in C++ for safe downcasting and runtime type checking in polymorphic class hierarchies. It's particularly useful when dealing with inheritance and when the exact type of an object needs to be determined at runtime. Unlike static_cast, dynamic_cast performs runtime checks, making it safer but also incurring a performance cost. It's commonly used for downcasting, cross-casting, and as part of Runtime Type Identification (RTTI) techniques. While dynamic_cast provides important safety features, its frequent use might indicate areas where the design could be improved. When used appropriately, dynamic_cast enhances type safety and enables more flexible handling of polymorphic types in C++ programs.

Previous Page | Course Schedule | Course Content