There are two problems with your code.
One, Element elements[3];
creates an array of Element
objects. Not of "objects of classes derived from Element
". You cannot store anything other than an Element
in such an array, and any attempt to do so results in object slicing: the non-Element
part of the source object is sliced away (discarded) and only the Element
part makes it in.
If you want dynamic polymorphism, you have to use pointers or references, and usually also dynamic allocation. In your case, this could look something like this:
std::unique_ptr<Element> elements[3];
Car c;
Adult a1;
Adult a2;
elements[0] = std::make_unique<Car>(c);
elements[1] = std::make_unique<Adult>(a1);
elements[2] = std::make_uniuqe<Adult>(a2);
Or, if you want to avoid copying the objects:
std::unique_ptr<Element> elements[3];
auto c = std::make_unique<Car>();
auto a1 = std::make_unique<Adult>();
auto a2 = std::make_unique<Adult>();
elements[0] = std::move(c);
elements[1] = std::move(a1);
elements[2] = std::move(a2);
Or just create them directly in the array:
std::unique_ptr<Element> elements[3];
elements[0] = std::make_unique<Car>();
elements[1] = std::make_unique<Adult>();
elements[2] = std::make_unique<Adult>();
Two, you're misinterpreting the result of dynamic_cast
. If dynamic_cast
succeeds, it returns the pointer cast to the appropriate type. If it fails, it returns a null pointer. Your condition is reversed, as you're interpreting == nullptr
as a success. The loop should actually look like this (with the unique_ptr
s from point #1 in place):
for(int i = 0; i< numElements; i++){
if(dynamic_cast<Adult*>(elements[i].get())){
cout << "Its an adult" << endl;
}else{
cout << "Sth else" << endl;
}
}
A few side notes:
Since your Element
is used as a polymorphic base class, it should have a virtual destructor. Otherwise, using a pointer of type Element
to delete a dynamically allocated object of a type derived from Element
will result in Undefined Behaviour (most likely memory corruption).
If your Element
is intended only as an abstract base and you never expect objects of type exactly Element
(not derived from it) to exist, you should make Element
abstract by giving it at least one pure virtual function (virtual void foo() = 0;
). If it's a real base class, it will probably naturally contain a few candidates for that.
Needing to know the exact derived type when working with a base class is often a sign of bad design. Ideally, Element
should contain virtual functions covering all functionality you may need to do with the objects in a type-abstracted manner. Exceptions exist, of course, but you should probably re-evaluate your design to make sure those dynamic_casts
are actually necessary.