Get type of a class inherited from a base class at runtime

 

The collection classes in the standard library allow us to, for example, create a list of objects which all inherit from CObject.

Obviously, this is useful because it allows us to store different types of object in the same list.

However, when one is subsequently working with the contents of the list, it is useful to be able to check at runtime what the actual subtype of the objects are, so you can branch accordingly. How is this done? I've tried overriding the Type() method on CObject for the subtype, but when calling this method it executes in the context of CObject. 

Example:

#include <Arrays\List.mqh>

class SubType : public CObject {
public:
   virtual int Type() {
      return 1;
   }
};

void OnStart() {
   CList list;
   
   list.Add(new CObject());
   list.Add(new SubType());
   
   for(CObject* obj = list.GetFirstNode(); obj != NULL; obj = list.GetNextNode()) {
      Print(IntegerToString(obj.Type()));
   }
}

Prints:
0
0

instead of the expected
0
1

What am I doing wrong here, and how can I achieve the desired result?

Many thanks

 

typename

 
Alain Verleyen:

typename


Thanks, but same issue - just get the CObject pointer type.

   for(CObject* obj = list.GetFirstNode(); obj != NULL; obj = list.GetNextNode()) {
      Print(IntegerToString(obj.Type()));
      Print(typename(obj));
   }


 
Hoodlum:

Thanks, but same issue - just get the CObject pointer type.


I think typename is used when using templates; but since you are using straight inheritance, you are just getting the type of the CObject* pointer.

Try const override.

class SubType : public CObject {
public:
   virtual int Type() const override
   {
                return 1;
   }
};
 
Hoodlum:

Thanks, but same issue - just get the CObject pointer type.


Sorry I read and answered too quickly.

Anthony is right.

 
Anthony Garot:

I think typename is used when using templates; but since you are using straight inheritance, you are just getting the type of the CObject* pointer.

Try const override.


Thank you, that fixed it - because the Type() method on the CObject base class is declared "const", the SubType version - which originally wasn't marked as "const" - wasn't overriding it. The desired result is also produced whilst omitting the "override" keyword on the SubType override - I presume you add this for compiler sanity check, that you are actually overriding what you think you are?

Cheers

override specifier (since C++11) - cppreference.com
  • en.cppreference.com
The identifier , if used, appears immediately after the declarator in the syntax of a member function declaration or a member function definition inside a class definition. In a member function definition inside a class definition, may appear in immediately after the declarator and just before . In both cases, , if used, is either or final...
 
Hoodlum:

Thank you, that fixed it - because the Type() method on the CObject base class is declared "const", the SubType version - which originally wasn't marked as "const" - wasn't overriding it. The desired result is also produced whilst omitting the "override" keyword on the SubType override - I presume you add this for compiler sanity check, that you are actually overriding what you think you are?

Cheers


exactly. In other cases it is sometimes necessary to use dynamic_cast

for(int i=0;i<list.Total();i++)
{
   MyObj *obj = dynamic_cast<MyObj*>(list.At(i));
   if(!CheckPointer(obj))
      continue;
   ...
}