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

To add comments, please log in or register
Hoodlum
25
Hoodlum  

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

Alain Verleyen
36058
Alain Verleyen  

typename

Hoodlum
25
Hoodlum  
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));
   }


Anthony Garot
1835
Anthony Garot  
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;
   }
};
Alain Verleyen
36058
Alain Verleyen  
Hoodlum:

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


Sorry I read and answered too quickly.

Anthony is right.

Hoodlum
25
Hoodlum  
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...
nicholi shen
1880
nicholi shen  
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;
   ...
}
To add comments, please log in or register