With your existing code, I actually would hope your compiler optimizes away the if-statement and your cast as this is pesimizing the code.
From the compiler's point of view, your code-base could be looking the following way:
struct A{
virtual void x();
};
struct B : A{
void x() override;
};
struct C : B{
void x() override;
};
So, when is sees your cast and function call: static_cast<B*>(a)->x() it still has to access the same virtual table as to when calling a->x() as there could be a potential class C.
(Please note that I use static_cast, as c-style casts are sources for bugs)
If you want to get a direct call to B, you better make the method or class final. Another good approach is using profile guided optimization, in which case, they often compare the vtable pointers.
To answer your side questions?
- Is the code legal? Yes, it is.
- Is this viable? Yes, given the remarks above.
- How slow will the dynamic_cast? Slow, I would argue to write a good benchmark for this, however, I wouldn't know how to do so and make it realistic.
- Is this good practice? No, it makes the polymorphism less usable.
- Will the static_cast be fast? Yes, it's fast, in this specific case, there ain't any instructions needed. Storing a pointer to B could both improve in specific cases of complex inheritance compared to the bool. If it would take extra memory, it could cause a decrease in performance as well. Another decrease could come well by just having extra assembly in your executable.
My advice, especially since you are new to C++: Don't do this or any other manual optimizations. Compilers can do a lot for you. Every manual optimization causes extra maintenance afterward, only use these kinds of tricks if you actually have a performance problem.
Oh, and if you want to know what the actual assembly code it, you can experiment at compiler explorer