c++inheritancedynamic-cast

Check if an instance of base class is one of some derived classes


I have a class Base, and it has many derived classes: Derived1, ...,Derived9.

Given an instance Base* b, is there a clean way to check whether b is an instance of either Derived1, ...,Derived5?

The obvious way is to check each one of them:

if (dynamic_cast<Derived1*>(b)) return true;
// ...
if (dynamic_cast<Derived5*>(b)) return true;

return false

This seems unnecessarily repetitive.

Ideally I would like to do something like:

const auto valid_derived_classes = {Derived1,...,Derived5};

for (const auto derived_class : valid_derived_classes)
{
    if (dynamic_cast<derived_class*>(b))
    {
        return true;
    }
}
return false;

Is there a way to accomplish something like this?

For context: I want to calculate the temperature of many types of devices, where each device is assigned some sensors. When all the sensors assigned to a device fail, it should measure the temperature according to some emergency sensors. There are few types of devices that should not do this. So when calculating the temperature, I need to check if a device is exceptional.


Solution

  • To answer your immediate question:

    Is there a way to accomplish something like this?

    You can write a variadic template that uses a fold expression for the dynamic_cast check:

    #include <iostream>
    #include <memory>
    
    struct B { virtual ~B() {} };
    struct D1 : public B {};
    struct D2 : public B {};
    struct D3 : public B {};
    
    // Check if  pointer to base (B) actually points to one of the derived (Ds):
    template <typename... Ds>
    bool is_one_of_derived(B* p) {
        return (... || dynamic_cast<Ds*>(p));
    }
    
    int main() {
        std::unique_ptr<B> p1 = std::make_unique<D1>();
        // Check if p1 is actually a D1 or D2:
        std::cout << std::boolalpha << is_one_of_derived<D1, D2>(p1.get()) << "\n";
    
        std::unique_ptr<B> p3 = std::make_unique<D3>();
        // Check if p3 is actually a D1 or D2:
        std::cout << std::boolalpha << is_one_of_derived<D1, D2>(p3.get()) << "\n";
    }
    

    Output:

    true
    false
    

    Live demo

    However-

    As @Jarod42 commented using dynamic_cast is usually a code-smell. You should consider an different solution, like using virtual methods.

    Reading your comments under the post (and the edit with the context) regarding the sensors, you can simply add a bool member (with a getter method), that will be set to true in the base class, and false in any derived that does not support it.
    You can also have a virtual double GetTemperture() method that polymorphically executes the relevant logic for each device.