0

I'm confused about polymorphism in C++. I'm studying it by myself, and I understood its main features. But I don't understand why it is helpful. Before studying polymorphism (about oop), I studied inheritance (that is helpful, because you can use a method in the superclass and subclass writing just only once). Now I'm stuck with polymorphism and the virtual keyword. I don't understand why it is helpful. See the code below (it's an exercise about C++ institute (I will get a certification)). Why can I declare as "virtual" only functions? I add in the code the variables n1, n2, n3 (as public), why cant I access them? I don't understand at all polymorphism, I read tons of posts about polymorphism on StackOverflow, but it's as if I understood polymorphism at 50%. I noticed that polymorphism is less difficult to understand in python because python doesn't have data types, but I want to understand it in C++ also, and its possible uses.

#include <iostream>
using namespace std;
class Pet {
    protected:
    string Name;
    public:
    Pet(string n) { Name = n; }
    virtual void MakeSound(void) { cout << Name << " the Pet says: Shh! Shh!"  << endl; }
    int n1;
};
class Cat : public Pet {
    public:
    Cat(string n) : Pet(n) { }
    void MakeSound(void) { cout << Name << " the Cat says: Meow! Meow!" <<       endl; }
    int n2;
};
class Dog : public Pet {
    public:
    Dog(string n) : Pet(n) { }
    void MakeSound(void) { cout << Name << " the Dog says: Woof! Woof!" << endl; }
    int n3;
};
int main(void) {
    Pet* a_pet1, * a_pet2;
    Cat* a_cat;
    Dog* a_dog;

    a_pet1 = a_cat = new Cat("Kitty");
    a_pet2 = a_dog = new Dog("Doggie");

    a_pet1->MakeSound();
    a_cat->MakeSound();
    static_cast<Pet*>(a_cat)->MakeSound();
    a_pet2->MakeSound();
    a_dog->MakeSound();
    static_cast<Pet*>(a_dog)->MakeSound();
}
Wyck
  • 10,311
  • 6
  • 39
  • 60
Riccardo
  • 192
  • 2
  • 2
  • 11
  • Now write a function that takes any Pet and call its `MakeSound` function. Assume you have 30 different Pet types, not just 2. Maybe the part you're missing is in the writing of functions that will take a pointer or reference to a base class. – PaulMcKenzie Aug 02 '19 at 19:10
  • 1
    Possible duplicate of [Why do we need virtual functions in C++?](https://stackoverflow.com/questions/2391679/why-do-we-need-virtual-functions-in-c) The accepted answer goes quite in depth with an example on *why* `virtual` functions are useful. – Fureeish Aug 02 '19 at 19:49
  • Where is your attempt to access `n1`, `n2`, and `n3`? Your prose suggests that your question might be focused on these three, but your code mostly ignores them. – JaMiT Aug 02 '19 at 20:10
  • OK, thanks @Fureeish. I just see the post. Yes i understood it, but i dont really know how to use it in real context, if i use it in small program it's ok, but other... – Riccardo Aug 03 '19 at 07:41
  • Consider catching `const std::exception&` and outputting its `what()` returned value. With `virtual` functions, you don't have to know the exact type of the exception to get meaningul information and results. – Fureeish Aug 03 '19 at 09:49
  • So I'm new to all of this, and I just have a question about the code. Is `int main(void)` the same as `int main()`? –  Aug 03 '19 at 17:19

3 Answers3

5

Perhaps an example can help. Consider a different main(), like this:

int main()
{
    std::vector<std::unique_ptr<Pet>> menagerie;
    menagerie.push_back(std::make_unique<Dog>("Fido"));
    menagerie.push_back(std::make_unique<Cat>("Morris"));
    menagerie.push_back(std::make_unique<Cat>("Garfield"));
    menagerie.push_back(std::make_unique<Dog>("Rover"));

    for (auto&& pet : menagerie)
    {
        pet->MakeSound();
    }
}

Here we have a bunch of pets. We can handle them all the same way, but they make different sounds. Calling MakeSound on each does the right thing for that particular kind of pet. This sort of use case is very common.

Fido the Dog says: Woof! Woof!
Morris the Cat says: Meow! Meow!
Garfield the Cat says: Meow! Meow!
Rover the Dog says: Woof! Woof!

Now, try removing the virtual keyword and they'll all say "Shh! Shh!".

Fred Larson
  • 60,987
  • 18
  • 112
  • 174
0

You are right, it's not easy to understand how polymorphism is useful and what it does when learning it. The common examples like you referred doesn't really help which merely demonstrates the concept but lacks real context.

The understanding and be able to use polymorphism is rather advance topic in programming. It is employed when following truly object oriented programming like SOLID and design patterns.

A good real world example of poloymophism in action is iterator design pattern. You define a base class say of a list with method like next(), then you can have different derived classes (for different kind of lists) all overriding this method and they implement it so you are able to iterate that list accordingly.

As you might be seeing it gets complicated so I can't explain everything here but you get an idea and some pointers.

zar
  • 11,361
  • 14
  • 96
  • 178
  • "but lacks real context" yes! Probably i undestood it, but i dont know where and when should i use it. And unfortunately i dont know how to get this skill. What can i do in your opinion? – Riccardo Aug 03 '19 at 07:46
  • @Riccardo I gave you pointers, look for iterator design pattern and see polymporphism in it. Another design pattern that uses polymorphism heavily is state design pattern but nearly all design patterns use it. – zar Aug 05 '19 at 14:27
0

The key idea of polymorphism is to have one method. This method will have different implementations, and a particular implementation is called based on certain situations.

Let's consider this example:

#include <iostream>
using namespace std;
class Polygon{

 protected:
  int numVertices;
  float *xCoord, *yCoord;

 public:
  void set(){
   cout<<"From Polygon"<< endl;
  }

};
class Rectangle : public Polygon{
public:

 void set(){
   cout<<"From Rectangle"<< endl;
}

class Triangle : public Polygon{
public:

 void set(){
   cout<<"From Triangle"<< endl;

 }
};
int main(){

 Polygon *poly;
 Rectangle rec;
 Triangle tri;

 poly = &rec;
 poly->set();
 poly = &tri;
 poly->set();
}

When you run this code your output is the following:

From Polygon
From Polygon

Let's add virtual to set() in base class (Polygon) . Here is what you get:

From Rectangle
From Triangle

If we have created a virtual function in the base class (Polygon) and it is being overridden in the derived class (In this case, Triangle and Rectangle) then we don’t need virtual keyword in the derived class, functions are automatically considered as virtual functions in the derived class.

The idea is set() will call the base class version of the method if set() is not virtual even if poly is pointed to Rect. On the other hand, set() that is virtual, it will call the actual method from the derived class. (In this case, rect->set() will print "From Rectangle").

Doing this means that in situations where I don't know the particular type of an object, I can use virtual and polymorphism and it will use the correct method during a call.

I hope this helps!

abhivemp
  • 932
  • 6
  • 24