0

So I have been programming in C++ for a while now, and I was told that using a dynamic cast to cast a pointer of an abstract class pointer to a different concrete class pointer was bad practice.

Shape* GeneralShape = new Triangle(...);
Triangle* triPtr = dynamic_cast<Triangle*>(GeneralShape);

Where Shape is an abstract class and Triangle inherits from it.

Using a dynamic cast just seems like a convenient way to access member functions when one of your inherited classes is just a little too different and needs more than the general functions that the abstract class contains. I was just wondering what's bad or what is the overhead in having run-time polymorphism?

  • 1
    "*what is the overhead in having run-time polymorphism?*" - `dynamic_cast` has to scan through the object's RTTI to discover whether `Triangle` really inherits from `Shape` and how to adjust a `Shape*` pointer into a `Triangle*` pointer. That takes time and effort at runtime. – Remy Lebeau May 03 '21 at 22:42
  • 3
    It's not as much of an overhead thing as a conceptual thing. You may be trading speed (and maybe not) for more easily understood and maintained code. Side note: When you find yourself making inherited class just a little too different, you could be pushing against the [Liskov Substitution Principle](https://stackoverflow.com/questions/56860/what-is-an-example-of-the-liskov-substitution-principle) and not have as good a candidate for inheritance as you thought. – user4581301 May 03 '21 at 22:42

1 Answers1

4

The "runtime overhead" of virtual dispatch is fairly low and not likely to matter except in tight loops:

  • Lookup of the correct function
  • Indirect call to function using its address
  • Pipeline stall if the CPU branch predictor mispredicted the call

dynamic_cast adds some additional overhead:

  • Walking the runtime representation of type inheritance to get the correct adjustment factor for the object pointer (or fail). This still is quite fast if the inheritance graph is not deep.

The larger cost is that of missed optimization opportunities at compile-time. In C++ in particular, using compile-time polymorphism (templates) very often results in a lot of inlining, elimination of loops, precomputation, etc. When run-time polymorphism is in play, these optimizations are generally not possible.

Interestingly, dynamic_cast is less of an obstacle to compile-time optimization because the compiler need only consider the two cases -- cast succeeds, and cast fails, which the programmer writes as two separate code paths both subject to optimization. In contrast, the "recommended" runtime polymorphism approach of using virtual calls is far more difficult to optimize because the set of possible types is open-ended.

Virtual calls are generally preferred over dynamic_cast (or tag-and-switch) for ease of maintenance (as @user4581301 comments), with performance considerations secondary.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720