user2896152
user2896152

Reputation: 816

Determinate an object type in c++

Let's suppose I have two classes mapping two objects that have the same interface

class FirstChild : class Father
{
    //some fields and methods useful for class A
}

class SecondChild : class Father
{
   //some fields and methods useful for class B
}

Later, in the code something like that is done

Father* myInstance = new SecondChild();

Now, if I want to know the type of the object such that some operation must be done if the instance is a FirstChild or SecondChild I'm doing something like that:

if (typeid (myInstance) == typeid (FirstChild))
{
     // do stuff
} else if (typeid (myInstance) == typeid (SecondChild))
       {
            // do other stuff
       }

Is this the correct way of doing that? Because somewhere on StackOverflow I read that typeid is not safe and it's more convenient to add a virtual function, let's say getType for example, and do, in FirstChild

char* getType { return "FirstChild"; }

To be honest, I don't like this solution too much because it seems that we bypass the poweful of the polymorphism in the Object-Oriented Programming.

So, you guys, what do you think? What's the best way to check the type of a child-object in c++?

Upvotes: 0

Views: 108

Answers (2)

Flynsee
Flynsee

Reputation: 596

One easy way to do this uses dynamic_cast. Example:

Father *myInstance = new SecondChild();
SecondChild *casted = dynamic_cast<SecondChild*>(myInstance);
if (casted != nullptr)
    std::cout << "myInstance is a SecondChild!";
else 
    std::cout << "myInstance is not a SecondChild!";

From: cppreference: dynamic cast

If the cast is successful, dynamic_cast returns a value of type new_type. If the cast fails and new_type is a pointer type, it returns a null pointer of that type. If the cast fails and new_type is a reference type, it throws an exception that matches a handler of type std::bad_cast.

As @Rob has pointed out, you can use a virtual function and let the object do the action itself.

struct Father 
{
    virtual void process() = 0;
};

You could use a virtual function to decide whether the action should be done, rather than checking the type.

struct Father 
{
    virtual bool shouldProcess() { return false; }
};
struct SecondChild : Father
{
    bool shouldProcess() override { return true; }
}

Upvotes: 0

HappyCactus
HappyCactus

Reputation: 2014

There are a couple of ways to do this.

typeid and dynamic_cast<> are the "official ways" to do that.

FirstChild *fptr = dynamic_cast<FirstChild>(myInstance);
if (fptr) {
  // do something
} else {
  SecondChild *cptr = dynamic_cast<SecondChild>(myInstance);
  if(cptr) {
     // do something else, and so on...
  }
}

But this is not the most elegant way to do this.

Another equivalent way is to have an "id type", like an enum or similar.

But as many said, if you need to know what the type is, you're probably doing it the wrong way.

An obvious alternative is to let the object do the specific action. Suppose you are using this code in a activate() function. Why not using a virtual doAction()?

class Father {
   public:
      virtual void doAction() = 0;
}

//...
myInstance->doAction();

There are variation of this, using different design pattern. But I guess you got the point.

Upvotes: 1

Related Questions