0
votes

I have a serious of if-else dynamic_cast to do downcast and perform specific subclass methods like the following. (I know using dynamic_cast may be considered something wrong in design.)

void cryout(const Animal* pAnimal)
{
    if(!pAnimal){ return; }
    ...
    if (auto pCat = dynamic_cast<const Cat*>(pAnimal))
    {
        pCat->meow();
    }
    else if (auto pDog = dynamic_cast<const Dog*>(pAnimal))
    {
        pDog->bark();
    }
    else
    {
        std::cerr << "No such animal.\n" ;
    }
}

Then I want to change to let the parameter passed by reference to not worry about null pointer issue.

void cryout(const Animal& animal)
{
    ...
    try
    {
        auto& cat = dynamic_cast<const Cat&>(animal);
        cat.meow();
    }
    catch (std::bad_cast)
    {
        try
        {
            auto& dog = dynamic_cast<const Dog&>(animal);
            dog.bark();
        }
        catch (std::bad_cast)
        {
            std::cerr << "No such animal.\n";
        }
    }
}

But this changes involve the stack unwinding when non-cat animal object passed in. AFAIK, stack unwinding could lead performance downgrade a lot. Is this casting by reference approach practical in my case?

BTW, isn't it strange to make "std::bad_cast exception" thrown in the normal working flow?

1
Why not just dynamic_cast<const Cat*>(&animal)?paddy
Is the dynamic_cast<const Cat&>(animla) not recommended to use?Chen OT
@ChenOT not if you are expecting it to fail regularly; exceptions are supposed to be only used for exceptional situationsM.M
I don't really see that either approaches are desirable in this case, as I would be more inclined to make a cryout a method. But if I absolutely had to use dynamic_cast, I would prefer the exception-free version for clarity.paddy
The std::bad_cast exception throwing is the only way to represent failure of casting reference, so I am wondering is the dynamic_cast by reference considered always succeeded or it will be a exceptional case.Chen OT

1 Answers

0
votes

Given little context, the solution would be something like this:

 #include <iostream>
 #include <string>

 struct Animal
 {
     virtual ~Animal() {}    
 };

 struct Dog : Animal {
     void bark() const { std::cout << "bark\n"; }
 };

 struct Cat : Animal {
     void meow() const { std::cout << "meow\n"; }
 };

 void cryout(const Animal& pAnimal)
 {
     if (auto pCat = dynamic_cast<const Cat*>(&pAnimal))
     {
         pCat->meow();
     }
     else if (auto pDog = dynamic_cast<const Dog*>(&pAnimal))
     {
         pDog->bark();
     }
     else
     {
         std::cerr << "No such animal.\n" ;
     }
 }

 int main()
 {
     Cat c;
     cryout(c);
     Dog d;
     cryout(d);
 }

But unless you have no choice - Animal should have a pure virtual function cryout() overriden in subclasses...