I have two classes, DerivedA
and DerivedB
that are derived from the same Base
class. Both classes hold pointers to an object each, which is of one of two data types, TypeA
and TypeB
, respectively. Those data types are derived from the same basic type BaseType
.
In the Base
class, I have an (abstract) getter for those pointers. That getter is overridden in the each of the derived classes and specified such that they should return the derived data types.
In the main
function, I define a vector that holds pointers to objects of both derived classes. But when I iterate over that vector, I only get BaseType
pointers instead of the expected TypeA
/TypeB
pointers.
The following MWE illustrates that:
#include <iostream>
#include <vector>
using namespace std;
class BaseType {};
class TypeA : public BaseType {};
class TypeB : public BaseType {};
class Base {
public:
virtual BaseType* GetObject() = 0;
};
class DerivedA: public Base {
public:
TypeA* object = new TypeA();
TypeA* GetObject() override {
cout << "i'm comming from DerivedA" << endl;
return object;
}
};
class DerivedB: public Base {
public:
TypeB* object = new TypeB();
TypeB* GetObject() override {
cout << "i'm comming from DerivedB" << endl;
return object;
}
};
int main() {
vector<Base*> vec = {new DerivedA(), new DerivedB()};
for (auto* item : vec){
auto* obj_ptr = item->GetObject();
cout << "I have an object of type " << typeid(obj_ptr).name() << endl;
}
}
which yields the following output:
i'm comming from DerivedA
I have an object of type P8BaseType
i'm comming from DerivedB
I have an object of type P8BaseType
Now, I have two questions the answers to which I hope to help me to understand how polymorphism in C++ works:
GetObject()
for each vector item clearly lands in the correct override, but does not return TypeA*
or TypeB*
, respectively, but a pointer to a BaseType
instead?TypeA
and TypeB
, respectively?There are two issues in your sample.
First, BaseType
is not polymorphic so typeid
will not use RTTI. Adding a virtual function solves this.
class BaseType {
public:
virtual ~BaseType() = default;
};
Second, typeid
inspects the dynamic type of its operand if possible, but does not special-case pointers. obj_ptr
itself is unequivocally of type BaseType *
, even if it points to a derived object. *obj_ptr
, on the other hand, is a BaseType &
which typeid(*obj_ptr)
will gladly query for its dynamic type.