What Type of Cast to Go from Parent to Child?

2019-02-25 07:08发布

问题:

This question is about which C++ style cast should be used to make this conversion. I am aware that a C style cast can achieve this.

For the following class structure:

class Foo {};

class Bar : public Foo {};

Say that I am given: Foo* ptr; and I want to cast it to a Bar* which type of cast should I be using? It seems like I must use dynamic_cast as it is:

Used for conversion of polymorphic types

I wanted to avoid dynamic_cast since it is a run time cast.

回答1:

You are correct that dynamic_cast is usually the most appropriate for this situation. However, if you know that the pointer is actually pointing to an object of the derived class, you can use static_cast for the conversion. If you're wrong and the pointer is not the derived class, you'll get undefined behavior.



回答2:

static_cast will work fine so long as you are sure that the object you are casting really is the type you expect it to be. Based on the example you gave, it looks like you are sure.



回答3:

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.