For the sake of clarity:
I wanted to avoid dynamic_cast
since it is a run time cast.
Well, you have a run-time type (given a statically-typed reference to the base-class, you can't generally know the dynamic type of the object), so a run-time cast is the only wholly safe option.
If you thought your object was really a Bar
, but were mistaken, dynamic_cast<Bar*>
will give you a nullptr
, or dynamic_cast<Bar&>
will throw an exception. Either way, you have a chance to deal with your run-time error at run time. As M.M pointed out, this is only available if your base class has or inherits at least one virtual method.
Now if, by chance, you can be statically certain the dynamic type of your object really is Bar
, you can use static_cast
. However, if you're mistaken, you have Undefined Behaviour and no opportunity to detect or deal with the error.
eg.
struct Foo { virtual ~Foo(){} };
struct Bar : public Foo {};
// safe, may return nullptr
Bar* safe_ptr_cast(Foo *f) { return dynamic_cast<Bar*>(f); }
// safe, may throw but you can catch it
Bar& safe_ref_cast(Foo &f) { return dynamic_cast<Bar&>(f); }
// unsafe - if you're wrong, you just broke everything
Bar* unsafe_ptr_cast(Foo *f) { return static_cast<Bar*>(f); }
By the way, if your issue with the run time cast is performance, risking UB in order to save notional time before you have code to profile is the definition of premature optimization.