6

I have Silly Question on OOPs concept, what is reason we go for polymorphism??

Simple code in C++:

class Shape{
public:
virtual void draw(){ cout<<"Shape"<<endl;};
};

class Traingle: public Shape
{
public: void draw(){cout<<"Triangle"<<endl;}
};

class Rectangle: public Shape
{
public: void draw (){cout<<"Rectangle"<<endl;}
};

int main(){
Shape *ptr= new Traingle();
ptr->draw();
delete ptr;
return 7;
}

Here ptr->draw() function will call the Triangle draw, if pointed to Rectangle then Rectangle draw, which is late binding.

What is necessity of creating Base class pointer and point it to different classes? We can create separate class object without any virtual function and call whicever needed. like

int main(){
    Traingle tObj; 
    tObj->draw();
    Rectangle rObj; 
    rObj->draw();
}

which basically does the same thing;

Why polymorphism basically? why virtual?

What is the need of it or what difference does it make using this property? And real case example would help!!

derekerdmann
  • 17,696
  • 11
  • 76
  • 110
Vijay M M
  • 81
  • 6
  • There is no need to new a pointer in your case. But that is unrelated to "what is the need (for) polymorphism..." – juanchopanza May 12 '16 at 15:03
  • The point of virtual functions is so that we can define behavior at runtime and allow for dynamic usage of objects. Polymorphism is the name given to this. – Lawrence May 12 '16 at 15:06
  • 1
    For example you may want to create collection of shapes. Consider ```std::vector```. It may contain different shapes but you can do common things to all of them. – isapego May 12 '16 at 15:06
  • Or create a *single* external function, `void drawMe(Shape& shape)`. Now call it twice, passing it a `Triangle` and `Rectangle` instance. There ya go. – WhozCraig May 12 '16 at 15:07
  • Possible duplicate of [Polymorphism in c++](http://stackoverflow.com/questions/5854581/polymorphism-in-c) – wally May 12 '16 at 15:08
  • Much can be said about polymorphism usefulness. However, one has to keep in mind that it's real life usage is far more limited than textbooks usually suggest. – SergeyA May 12 '16 at 15:22

5 Answers5

3

Imagine a base class Shape. It exposes a GetArea method. Imagine a Square class and a Rectangle class, and a Circle class. Instead of creating separate GetSquareArea, GetRectangleArea and GetCircleArea methods, you get to implement just one method in each of the derived classes. You don't have to know which exact subclass of Shape you use, you just call GetArea and you get your result, independent of which concrete type is it.

Have a look at this code:

#include <iostream>
using namespace std;

class Shape
{
public:
  virtual float GetArea() = 0;
};

class Rectangle : public Shape
{
public:
  Rectangle(float a) { this->a = a; }
  float GetArea() { return a * a; }
private:
  float a;
};

class Circle : public Shape
{
public:
  Circle(float r) { this->r = r; }
  float GetArea() { return 3.14f * r * r; }
private:
  float r;
};

int main()
{
  Shape *a = new Circle(1.0f);
  Shape *b = new Rectangle(1.0f);

  cout << a->GetArea() << endl;
  cout << b->GetArea() << endl;
}

An important thing to notice here is - you don't have to know the exact type of the class you're using, just the base type, and you will get the right result. This is very useful in more complex systems as well.

Vtik
  • 3,073
  • 2
  • 23
  • 38
3

Polymorphism allows reuse of code by allowing objects of related types to be treated the same.

Consider that you might need dozens of subclasses that behave differently:

struct Shape1: public Shape { /* .. */ }; // triangle
struct Shape2: public Shape { /* .. */ }; // rectangle
// ...
struct ShapeN: public Shape { /* .. */ }; // projection of rhombic triacontahedron

Consider that you might need to process objects pointed by an array of Shape pointers.

With polymorphism, you need a single vector, and a single loop with virtual function calls:

std::vector<Shape*> v = get_shape_vector();
for(Shape* s : v)
    s->draw();

Without polymorphism, you would have manage a separate array for each type and process them separately:

std::vector<Shape1> v1 = get_shape1_vector();
std::vector<Shape2> v2 = get_shape2_vector();
// ...
std::vector<ShapeN> vN = get_shapeN_vector();

for(Shape1& s : v1)
    s.draw();
for(Shape2& s : v2)
    s.draw();
// ...
for(ShapeN& s : vN)
    s.draw();

The 3 lines of code using polymorphism are way easier to maintain than the 3*N lines of code not using polymorphism.

Consider that you might need to modify the process. Perhaps you want to add a function call before drawing. This is simple when you have polymorphism on your side:

void pre_draw(Shape*);

for(Shape* s : v) {
    pre_draw(s);
    s->draw();
}

Without polymorphism, you need to define dozens of functions and modify each of the dozen loops:

void pre_draw1(Shape1&);
void pre_draw2(Shape2&);
// ...
void pre_drawN(ShapeN&);

for(Shape1& s : v1) {
    pre_draw1(s);
    s.draw();
}
for(Shape2& s : v1) {
    pre_draw2(s);
    s.draw();
}
// ...
for(ShapeN& s : v1) {
    pre_drawN(s);
    s.draw();
}

Consider that you may add shapes later. With polymorphism, you simply need to define the new type, and the virtual function. You can simply add pointers to it into the array and they will be processed just like objects of every other compatible type.

struct ShapeN1: public Shape { /* .. */ }; // yet another shape

Without polymorhpism, besides defining the new type, you would have to create a new array for it. And you would need to create a new pre_draw function. And you would need to add a new loop to process them.

void pre_drawN1(ShapeN1&);
// ...
std::vector<ShapeN1> vN1 = get_shapeN1_vector();
// ...
for(ShapeN1& s : vN1) {
    pre_drawN1(s);
    s.draw();
}

In fact, you would need to go through your entire code base for places where each of the shape type is processed and add the code for the new type there.


Now, N might be small or great. The greater N is, the more repetition polymorphism avoids. But, no matter how few subclasses you have, not having to look through your entire code base when you add a new one is a great boon.

eerorika
  • 232,697
  • 12
  • 197
  • 326
0

Imho the best example for using polymorphism is a container:

std::vector<Shape*> shapes;
shapes.push_back(new Triangle());
shapes.push_back(new Rectangle());

you can iterate through this container without caring about what is the actual type of the objects:

for (int i=0;i<shapes.size();i++){
    shapes[i]->draw();
}
463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
0

Simply put, polymorphism allows you to put different shapes in the same box, and treat everything in the box in a heterogeneous way.

extending your example:

#include <iostream>
#include <memory>
#include <vector>

class Shape{
public:
    virtual void draw(){ std::cout<<"Shape"<< std::endl;};
};

class Traingle: public Shape
{
public:
    void draw() override
    {
        std::cout<<"Triangle"<< std::endl;
    }
};

class Rectangle: public Shape
{
public:
    void draw() override
    {
        std::cout<<"Rectangle"<< std::endl;
    }
};

int main(){

    std::vector<std::unique_ptr<Shape>> box_of_shapes;

    box_of_shapes.emplace_back(new Traingle);
    box_of_shapes.emplace_back(new Rectangle);

    for (const auto& pshape : box_of_shapes)
    {
        pshape->draw();
    }

    return 0;
}

Rectangle is a Shape (because it's publically derived from Shape) Therefore it can be held by a vector that deals in (pointers to) Shape. However, because the draw method is virtual, a Rectangle will draw correctly even if the caller is only thinking of it as a Shape.

expected output:

Triangle
Rectangle
Richard Hodges
  • 68,278
  • 7
  • 90
  • 142
0

The magic word is decoupling. Let's say you are creating an application to manage the storage of a supermarket. You pretty much know from the beginning that you will need sooner or later a way to store and retrieve data. However, you don't know which is the best technology to use yet(it could be a relational database or a NoSql one for example).

So, you create an interface (abstract class):

struct Serialize{
    virtual void save(Product product) = 0;
    ... other method here ...
};

Now, you can carry on with the development of the other parts of the application just implementing an in memory version of Serialize.

class InMemorySerialize : public Serialize {
    ... implement stuff here ...
};

The code that depend on Serialize doesn't care which concrete class is using, the only place that really need to be changed to modify the serialize implementation is the construction of the concrete class. But the construction of the class is likely to be in only one place and pretty close to the main function (look at strategy pattern for more information).

//in the main (switching these lines you will use different implementations)
//the rest of your code will not change
unique_ptr<Serialize> serializer(new InMemorySerialize());
//unique_ptr<Serialize> serializer(new OnFileSerialize(myfolder));

Also, implementing an interface is one of the simplest method to fulfill the Open/Close principle. If you want to support a serialization to file instead of in memory, you are going to create a new class that will be in a separate file. So, you are open to increase the functionality of your application without touching the existing code.

As a final remark, testing is much easier if you depend upon interfaces instead of concrete object. You can easily implement the behavior that you need for your test.

Alessandro Teruzzi
  • 3,918
  • 1
  • 27
  • 41