Grumpy ol' Bear
Grumpy ol' Bear

Reputation: 745

How do I ask if an object belong to a class x?

So I've got Shape.h, Rectangle.h, Circle.h and main.cpp.

Shape.h got:

class Shape{
public:
    Shape() {};
    ~Shape() { cout << "Destroy Shape."; };

    virtual double getArea() = 0;
    virtual double getCircumference() = 0;
};

Rectangle and Circle their respective code.

Now in main.cpp I do

Shape* newRectangle= new Rectangle(4, 8);
Shape* newCircle= new Circle(10);

All fine and dandy so far. Here's where I'm stumped. I know what I have to do, I just don't know HOW to do it.

I'm trying to write a function that checks if a Shape* Object belongs to Circle or not.

It goes something like this

if Shape* object belongs to Object-Type Circle, then
cout << "It's a Circle, bruh!";
else
cout << "Ain't a circle, yo!";

I started after googling with that:

void check(Shape & object){
    Circle& checkObject = dynamic_cast<Circle&>(object);

}

The function in main will be called via:

check(*newRectangle);
check(*newCircle);

But I haven't got a clue how to go on :(. Any help and explanation is appreciated. Thank you!

Upvotes: 2

Views: 104

Answers (2)

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726499

You can do it by dynamically casting the Shape pointer to a pointer of desired type, and checking for nullptr:

if (dynamic_cast<Circle*>(object)) {
    cout << "It's a Circle, bruh!";
}

This requires that Runtime Type Information is turned on, and that your object has at least one virtual function (it does).

Note 1: if you have to do something like that, see if you could change your design so that you wouldn't have to do this. For example, you could apply a multiple dispatch pattern, such as Visitor, to avoid this check:

struct ShapeVisitor {
    virtual ~ShapeVisitor() {}
    virtual void visitCircle(const Circle* circle);
    virtual void visitRectangle(const Rectangle* rectangle);
};

class Shape{
public:
    Shape() {};
    virtual ~Shape() { cout << "Destroy Shape."; };

    virtual double getArea() = 0;
    virtual double getCircumference() = 0;
    virtual void Accept(const ShapeVisitor& visitor) = 0;
};

struct Circle : public Shape {
    virtual void Accept(const ShapeVisitor& visitor) {
        visitor.visitCircle(this);
    }
};

struct Rectangle : public Shape {
    virtual void Accept(const ShapeVisitor& visitor) {
        visitor.visitRectangle(this);
    }
};

Now you can print the kind of shape you see like this:

struct PrintTypeVisitor : public ShapeVisitor {
    virtual void visitCircle(const Circle* circle) {
        cout << "It's a Circle, bruh!";
    }
    virtual void visitRectangle(const Rectangle* rectangle) {
        cout << "It's a Rectangle, bruh!";
    }
}
...
PrintTypeVisitor v;
Shape* object = ...
object.Accept(v); // This prints dynamic type of the object

Note 2: You need to make Shape's destructor virtual.

Upvotes: 4

R Sahu
R Sahu

Reputation: 206567

  1. Try to avoid logic based on derived types. Use virtual member functions whenever you can.

    class Shape {
       public:
          virtual void print(std::ostream& out) const = 0;
       ...
    };
    

    and implement the function in the derived clases.

    class Circle : public Shape {
       public:
          virtual void print(std::ostream& out) const
          {
             out << "Got a Circle.\n";
          }
    
       ....
    };
    
  2. If you cannot solve your problem using a virtual member function, you'll need to resort to dynamic_cast.

    Shape* shapePtr = <some pointer>;
    Circle* circlePtr = dynamic_cast<Circle*>(shapePtr);
    if ( circlePtr ) {
       // Access Circle functionality.
    }
    

Upvotes: 6

Related Questions