问题
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.
回答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
回答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);
回答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.
回答4:
Above answers are good, conceptually you can think like this,
Your Car
object which is derived from Vehicle
class. You can refer Car
as Vehicle
, and can convert to Car
as it originally belonged to Car
. But it will be a problem if your Vehicle
object actually representing Bike
and trying to convert to Car
. Thats why you need safe casting.
class Vehicle
{
...
};
class Car : public Vehicle
{
...
};
class Bike : public Vehicle
{
...
};
int main(int argc, char const *argv[])
{
Vehicle* vehicle = new Car();
Car* old_car = dynamic_cast<Car *>(vehicle);
if(old_car) {
// OK Vehicle is Car, use it
}
vehicle = new Bike();
old_car = dynamic_cast<Car *>(vehicle);
if(old_car) {
// No Vehicle isn't Car, this code won't execute
}
return 0;
}
来源:https://stackoverflow.com/questions/24851067/c-polymorphism-from-parent-class-to-child