C++ Polymorphism: from parent class to child

22,926

Solution 1

"but is there any way to convert it back: from parent, which was obtained from child, give child class back?"

Yes, as mentioned in the other answers, there are two ways to do this.

Child * old_child = dynamic_cast<Child*>(parent);

The result of the dynamic_cast<> can be checked at runtime, thus you can determine if the parent object really represents a Child instance:

if(!old_child) {
     // parent is not a Child instance
}

Also note to get this working properly, the classes in question need to have a vtable, that RTTI can actually determine their relation. The simplest form to achieve this, is giving the Parent class a virtual destructor function

class Parent {
public:
    virtual ~Parent() {}
    // or
    // virtual ~Parent() = default;
    // as suggested for latest standards
};

NOTE:
If this should apply to a general design decision, I would strongly disregard it. Use pure virtual interfaces instead, that are guaranteed to be implemented, or not.


The second way of static_cast<> can be used in environments, where you well know that parent actually is a child. The simplest form of this is the CRTP, where Parent takes the inheriting class as a template parameter

template <class Derived>
class Parent {

     void someFunc() {
         static_cast<Derived*>(this)->doSomething();
     }
};

class Child : public Parent<Child> {
public:
    void doSomething();
};

The validity of an instatiation of Parent<> and static_cast<> will be checked at compile time.

NOTE:
Another advantage is that you can use an interface for derived that makes use of

  • static class members of Derived
  • typedef's provided by Derived
  • ... more class traits, that can be checked at compile time

Solution 2

You need to cast the object back to child. This is done like this:

 Child * old_child = static_cast<Child*>(parent);

and

 Child * old_child = dynamic_cast<Child*>(parent);

Solution 3

int main() { 
   Parent parent;
   Child child;

   // upcast - implicit type cast allowed
   Parent *pParent = &child; 

   // downcast - explicit type case required 
   Child *pChild = (Child *) &parent;
}

You should use the dynamic_cast to do this safely:

Child *p = dynamic_cast<Child *>(pParent)

EDIT

With dynamic_cast returns a null pointer if the type is not apart of the base class, also casting to a reference throws a bad_cast exception. dynamic_cast is particularly useful if you do not know what the object type will be.

On the other hand static_cast:

Child *p = static_cast<Child *>(pParent)

This assumes that you want to reverse an explicit conversion and perform no runtime checks. This allows for flexibility but must be used with caution.

The regular downcast shown above:

Child *pChild = (Child *) &parent;

Is a C-style down cast (like a static_cast), which may also cast to a private base class (not sure about, multiple inheritance), while static_cast would cause a compile-time error. Things like numeric conversions is a good example to use this on.

Share:
22,926
user2160982
Author by

user2160982

Updated on July 22, 2020

Comments

  • user2160982
    user2160982 almost 4 years

    In C++ we can convert child class pointer to parent, but is there any way to convert it back: from parent, which was obtained from child, give child class back?

    I mean:

    class Parent
    {
        ...
    };
    
    class Child : public Parent
    {
        ...
    };
    
    int main(int argc, char const *argv[])
    {
        Child* child = new Child();
        Parent* parent = child;
        Child* old_child = parent; // how to do this??
        return 0;
    }
    

    Thank you for your answers.

  • πάντα ῥεῖ
    πάντα ῥεῖ almost 10 years
    Would you mind to explain a bit more about the differences and actual behavior of these two cast methods.
  • Deduplicator
    Deduplicator almost 10 years
    The result of the dynamic_cast can be ... iff the base class is a true polymorphic type, aka has at least one virtual function or base. Otherwise it degrades to static_cast (It will be strength-reduced to static_cast when provably correct in any case).
  • πάντα ῥεῖ
    πάντα ῥεῖ almost 10 years
    @Deduplicator THX! Better now?
  • Deduplicator
    Deduplicator almost 10 years
    Yes, +1. BTW: Using = default; instead of {} for the dtor body might be slightly longer but does not prevent the class from being trivial, with all attendent benefits (though it needs a slightly more modern compiler).
  • πάντα ῥεῖ
    πάντα ῥεῖ almost 10 years
    In which way this answer adds any value compared to the other answers, besides replacing Parent/Child with a Vehicle/Car metaphor?
  • David Pullar
    David Pullar almost 10 years
    updated answer to explain a bit about the safety issues