markzzz
markzzz

Reputation: 47995

Is it possible to call the (same name) child function without using virtual keyword?

I'm just curious. Here for example:

#include <iostream>

class Polygon {
  protected:
    int width, height;

  public:
    Polygon (int a, int b) : width(a), height(b) {}

    int area() { return 0; };
};

class Rectangle: public Polygon {
  public:
    Rectangle(int a,int b) : Polygon(a,b) {}

    int area() { return width*height; }
};

int main () {
  Polygon * ppoly1 = new Rectangle (4,5);
  std::cout << ppoly1->area() << std::endl;
  delete ppoly1;
}   

Can I call the area() function of the object Rectangle without set virtual area() on Polygon? Or it's impossible and Rectangle's area() will always be ignored without parent's virtual?

Upvotes: 1

Views: 85

Answers (3)

463035818_is_not_an_ai
463035818_is_not_an_ai

Reputation: 123084

If the function is not virtual, the compiler decides what function to call based on the type of the pointer (not on the actual type of the object), thus you can use a cast:

std::cout << static_cast<Rectangle*>(ppoly1)->area() << std::endl;

WARNING: The static cast is fine in this case, because you know for sure that the cast will succeed. In general this is not the case and you might get undefined behaviour if the cast does not succeed.

Also note, that the code you show here (I assume that this is just a simplified example) is a typical example for declaring the method virtual. Only if you have strong reasons not to do so you would look for a different solution (e.g. take a look at @axalis answer).

Upvotes: 6

EmDroid
EmDroid

Reputation: 6046

One possibility is compile-time polymorphism (CRTP):

template<class IMPL_T>
class Polygon {
  protected:
    int width, height;

  public:
    Polygon (int a, int b) : width(a), height(b) {}

    int area() { return static_cast<IMPL_T *>(this)->area(); };
};

class Rectangle: public Polygon<Rectangle> {
  public:
    Rectangle(int a,int b) : Polygon(a,b) {}

    int area() { return width*height; }
};

But note that then you cannot have a base class pointer (because base of each object is a different type). The use is, again, via templated calls.


In cases where you really need a runtime polymorphism (i.e. pointer to a base class), virtual call is normally the best solution, it is not likely you'll be able to roll out something better on your own (for example, replacing by switch on type getter combined with static casts is not only uglier but in many cases also worse performance, and dynamic_cast is much slower than calling a virtual method).

Upvotes: 2

Vittorio Romeo
Vittorio Romeo

Reputation: 93334

Can I call the area() function of the object Rectangle without set virtual area() on Polygon?

Yes, you can static_cast a Polygon* to a Rectange* if you are sure that the pointer is actually pointing to a Rectangle:

Polygon * ppoly1 = new Rectangle (4,5);
auto asRectangle = static_cast<Rectangle*>(ppoly1);
std::cout << asRectangle->area() << std::endl;

Upvotes: 0

Related Questions