Reputation: 10499
I have a base class (car
) and a class that inherit the base class (honda
):
class car
{
virtual void polymorphic_class()
{ }
};
class honda : public car
{ };
When I use the following code and I cast my class a get a null pointer:
list<car> cars;
honda h;
cars.push_back(h);
honda* h_ptr = dynamic_cast<honda*>(&cars.back());
// h_ptr is NULL
Why? How I have to cast properly my object?
Upvotes: 1
Views: 144
Reputation: 254431
Polymorphism works on pointers and references, not on object instances.
In this case, your list contains objects of type car
, not of any derived type. When you insert a honda
, it will copy the car
part and ignore the rest; this is sometimes referred to as slicing.
For polymorphism, you could use a list of pointers:
list<car*> cars {new honda};
honda * h_ptr = dynamic_cast<honda*>(cars.back()); // should be a valid pointer
NOTE: If you do allocate using new
as in my example, remember to either delete
them, or store smart pointers (like std::unique_ptr<car>
) rather than raw pointers. You'll also need a virtual destructor in order to delete objects using a base-class pointer.
You can avoid the slicing problem by making the base class abstract; if it contains pure virtual functions, then you can't instantiate objects of that type, only of derived types that override those functions:
class car
{
virtual ~car() {}
virtual void do_something() = 0;
};
class honda : public car
{
void do_something() {}
};
If you don't actually want an abstract interface (e.g. if you only access derived-class functionality using dynamic_cast
rather than through virtual functions), then you could make the destructor pure virtual instead; then the derived classes won't have to explicitly override anything. The base class destructor must still be implemented and, due to a quirk of the language, that implementation must be outside the class definition:
class car
{
virtual ~car() = 0;
};
inline car::~car() {}
class honda : public car {};
This is a somewhat unusual approach, since polymorphism through virtual functions is usually more efficient and more convenient.
Upvotes: 2
Reputation: 1708
Try this
list<car*> cars;
honda *h = new honda();
cars.push_back(h);
honda* h_ptr = dynamic_cast<honda*>(cars.back());
This works.
Upvotes: 0
Reputation: 258548
The reason this doesn't work is object slicing. The objects in cars
are no longer honda
s, but just cars.
You need a vector of pointers or smart pointers:
list<car*> cars;
honda h;
cars.push_back(&h);
honda* h_ptr = dynamic_cast<honda*>(cars.back());
I'd actually change the design and make car
abstract (pure virtual destructor or something). That way you'll also get a compilation error.
Upvotes: 4