C++ Polymorphism: from parent class to child
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 byDerived
- ... 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.
user2160982
Updated on July 22, 2020Comments
-
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 yearsWould you mind to explain a bit more about the differences and actual behavior of these two cast methods.
-
Deduplicator almost 10 yearsThe 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 almost 10 yearsYes, +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 yearsIn which way this answer adds any value compared to the other answers, besides replacing
Parent
/Child
with aVehicle
/Car
metaphor? -
David Pullar almost 10 yearsupdated answer to explain a bit about the safety issues