I don't understand Polymorphism at all?

Hi guys Im new to this forum so I don't really know how Im supposed to ask this question, whether to ask for code or whatever.

So Im a self taught C++ programmer, I covered almost all the basic concepts (Variables, arrays, functions, classes, inheritance, etc) and my last topic that Im going to cover is Polymorphism. Problem is, there's very little to no videos or tutorials that are easy enough for me to understand. Im only 14 years old so yeah.. My question is can someone maybe explain to be the basics of Polymorphism? Or possible find an easy enough tutorial for me to understand. I've been looking for 3 days already and nada. I don't understand, is this not an important topic? I have no previous experience with Polymorphism whatsoever.

Your help is greatly appreciated!
Polymorphism stems from inheritance. The whole idea is that you have a general base class and more specific derived classes. You can then write code that works with the base class... and polymorphims makes your code not only work with the base class, but all derived classes.

The classic example is the "Area" function. Let's say we have 3 different kinds of shapes:
- Circle
- Square
- Triangle

As you should know, the way to calculate the area is different for all these shapes. So a polymorphic solution would be the following:

1
2
3
4
5
class Shape  // an abstract base class to represent a shape
{
public:
  virtual int Area() = 0;  // a pure virtual function to calculate the area
};


Derived classes would look something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
class Square : public Shape
{
private:
  int width;
  int height;

public:
  virtual int Area()
  {
    return width * height;  // area of a square
  }
};

//==========

class Triangle : public Shape
{
private:
  int width;
  int height;

public:
  virtual int Area()
  {
    return width * height / 2;  // area of a triangle
  }
};

//======================

class Circle: public Shape
{
private:
  int radius;

public:
  virtual int Area()
  {
    return radius * radius * pi;  // area of a circle
  }
};



The reason this is advantageous is it allows you to call the Area function from the base class 'Shape' (or from just a Shape pointer) and it will properly call the correct Area function based on what type of shape it actually is. This means you can write code that will work with ANY shape, not just with circles or squares or triangles.

For example:

1
2
3
4
5
6
7
void func(Shape* shape)
{
  // do a bunch of stuff with your 'shape' here.

  // print the area of the shape:
  cout << "The area of this shape is:  " << shape->Area();
}


This 'func' function will work with any and all shapes. You don't have to write a different one for each shape.

This is what polymorphism is about.
Sorry, I still don't get it :s
So all there is a new keyword called virtual. Can you put it in more simpler terms please?
Disch gave a very concrete example using pure virtual functions (and some base class pointers), I'll give you a bit more of a common situation where Polymorphism comes in. Let's say that you create a game, in which the player can face different enemies. They all have something in common though; no matter if it's a dragon, a soldier, a farmer or a firefly, they can all attack and have a certain hp. Let's say that we want to create groups of enemies by using a vector of base class pointers (note that this is not a recommend method, use boost::ptr_vector instead). We could then do something among the following lines:
1
2
3
vector<Enemy*> Mob;
Mob.push_back(new Dragon(/* call the constructor for a dragon here */));
Mob.push_back(new Orc(/* call the constructor for an orc here */));
This code assumes you have an Enemy class defined which has public derivations known as Dragon and Orc.

At a more abstract level, you could say that Polymorphism allows you to refer to something('s pointer) as it's parent('s pointer).
Last edited on
It doesn't get much simpler than that. =x The problem is it's a kind of complicated subject.

Here's a simple example that you can compile and try out:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <iostream>
using namespace std;

class Parent
{
public:
  virtual void func() = 0;
};

class A : public Parent
{
public:
  virtual void func() { cout << "Calling from class A.\n"; }
};

class B : public Parent
{
public:
  virtual void func() { cout << "Calling from class B.\n"; }
};

//=====================

void Test(Parent* p)
{
  /*  Since this function takes a 'Parent' pointer and not a A or B pointer, it will work with ANY
    object derived from Parent... not just A or B.  Therefore you can call this function with either
    A or B and it will still work fine!

    What's more, this function doesn't need to know whether 'p' points to an A or B.  And really,
    it shouldn't know (if it knew, then it would probaly only work with A or B and not with any
    other type.
  */

  p->func();  // this will call the appropriate function from A or B, depending on what type
   // 'p' points to.
}


int main()
{
  A a;
  B b;

  // because A and B are both derived from Parent, we can call our test function with either of
  //  them:
  Test(&a);
  Test(&b);

  return 0;
}


Hopefully this will clarify it?



EDIT:

There's a key concept to understand here, which my latest example doesn't show very well.

Inheritance forms an "is a" relationship. For example, in my first example, Circle is derived from Shape. This implies that Circle "is a" Shape. Anything you can do with a Shape, you can also do with a Circle. (Of course that doesn't mean that all Shapes are circles).

Kyon's example illustrates that as well. Dragon "is a" Enemy. Therefore anything you can do with an Enemy you can also do with a Dragon.

Polymorphism takes that a step further by letting you do child-specific things with parent-general code.

For example, let's say that all Enemies can attack, but the way they attack is different depending on the Enemy. A Dragon would breathe fire on you, while an Orc would club you... so you would want different code for each.

Without polymorphism, you'd have to do something like this:

1
2
3
4
if(myenemy->type == TYPE_DRAGON)
  ((Dragon*)myenemy)->BreatheFire();
else if(myenemy->type == TYPE_ORC)
  ((Orc*)myenemy)->BashWithClub();


That would be necessary because you'd have to downcast from the general "Enemy" class to the more specific "Dragon/Orc" classes. This makes it impossible to write code that will work with any enemy, because every time you need to do something specific, you have to put in a giant else if chain.

With polymorphism, you can juts make a virtual "Attack" function, and have the appropriate attack happen automatically:

1
2
myenemy->Attack();  // will breath fire or bash with club automatically
  // depending on the type of the enemy 
Last edited on
Polymorphism means "many forms". It is where one type of thing comes in many forms. So you can treat it according to its type, but it will behave differently according to which form of that type it happens to be.
Last edited on
So basically what it does is it let's you take one part from the parent class and if you put virtual infront of it, you can use it anywhere?
If by anywhere, you mean refer to shape->Area() where shape is a pointer to an instance derived from Shape then yes, with one caveat. One thing that has not been explained so far is "pure virtual".

Going back to Disch's first example, in class Shape the definition for the Area method has the notation "= 0" after it. That indicates that Shape does NOT have an implementation of the Area function and that the Area function is implemented in each derived classes (square, triangle, circle, etc). This is called a "pure virtual" function. This also makes Shape an abstract base class and you would get an error if you tried to instantiate Shape directly. It's also an error to derive a class from Shape that does not have an Area fuction.



Last edited on
C0D3 wrote:
So basically what it does is it let's you take one part from the parent class and if you put virtual infront of it, you can use it anywhere?

No...

It let's you do tasks that are specific to different derived classes, without having to know exactly which derived class you're working with.

This means you can write code that works with an abstract parent class... and that code will in turn work with any derived class.

Here's another example... (this example is basically what iostream does... but nevermind that):

Let's say you have an abstract parent class called "File". This class has a pure virtual "Read" function that reads an int from the file and returns it:

1
2
3
4
5
class File
{
public:
  virtual int Read() = 0;
};


Because the function is pure virtual, it has no body. It is assumed that derived classes will fill in their own body for it. But we can still call it from code.

Now let's say we have data that we want to load from a file:

1
2
3
4
5
6
7
8
void MyClass::Load(File* file)
{
  mydata = file->Read();
  otherstuff = file->Read();
  for(int i = 0; i < X; ++i)
    myarray[i] = file->Read();
  //...
}


The File class creates an "abstract interface" that our code can use. This class represents a concept. The File class represents some kind of file (but we don't know exactly what kind of file), and the Read function reads from that file and returns the data.

The key here is that different kinds of files will read the data different ways.

Normal files will just read it off the disk. But what if the file is zipped or compressed or something? You could have a separate class for zipped files and just derive from File and use the same abstract interface. That way any code that reads from a File could also read from a ZippedFile because a ZippedFile "is a" File.

The actual loading code doesn't have to know or care where the data is coming from or how it's getting there.

Without polymorphism, you might have to write two entirely different loading functions. One that loads from a normal file and one that loads from a zipped file. And even then it would only work with those 2 types of files. If you add a future type later (like a .7z or .rar file, or a file over an internet connection, etc) you'll have to keep writing more and more versions of the same function.

But with polymorphism, you can just deal with that abstract interface. Future classes can be created, and any old code that uses the abstract interface will work with your new classes without you having to modify any old code.
Last edited on
What do you mean by abstact and virtual?
"abstract" sort of means it's a "concept". If something is abstracted, you don't know (or care) how it works.

In C++, abstract classes don't even do anything by themselves, they just have an interface that other classes will use.

In my previous example, the class "File" is abstract because it has a "pure virtual" function. This function has no body. All it does it is creates an interface (with that 'Read' function) so that any code using "File"s can read data.... but exactly how the data is read isn't known.

Because of this abstraction... because the details of how the code works are separated from the interface... it allows us to create multiple implementations, all of which can be used interchangably in the same fashion.


I don't think I can explain it any more than I did in my previous post. If you have a specific question about it though I'm happy to try and answer. It's a difficult concept to grasp, but once you get it, it's super cool.
It's not the problem how you're explaining it, it's just the vocab :( Im only 13 and yeah... if there's no easier way to explain it though I'll understand. Sorry for my incappabilities.
I guess the vocabulariy is a little weird. =P

Don't worry about what the words mean too much, just focus on the concept.

Here's another (hopefully more simple) example of how abstraction/polymorphism can be used:

1
2
3
4
5
6
7
8
void MyOutput(ostream& s)
{
  // output a bunch of data
  s << "This is my data:\n"
  s << myvar << "\n";
  s << anothervar << "\n";
  s << etc << "\n";
}


This code dumps a bunch of data to an "ostream". We know an ostream is something that we output data to. But then what? What does the ostream do with the data after it gets it? The answer to this question is very important... and here it is:

we don't know, and we don't care

That's what makes ostream abstract. It could be doing ANYTHING with the data we're giving it. We don't have the foggiest idea what it's doing. What's more, we shouldn't know what it's doing.

This is a good thing because it allows the above code to be used with any kind of output device... not just a single output device.

For example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// cout is an ostream that outputs to the console
//  so we can output to cout by doing this:
MyOutput( cout );

// or.. instead... if we want to write to a file instead of printing
//  to the console... ofstream is an ostream:
ofstream myfile("myfile.txt");
MyOutput( myfile );

// or if we just want it to print to a string we want to keep in memory
//  and use later
stringstream ss;
MyOutput( ss );  // stringstream is an ostream
string mystring = ss.str();  // now we have it in a string 


But that's not all. Those are just the most common ones. You could have an ostream that does speech synth and speaks the output to the user through ths speakers. Or one which makes the monitor flash bright colors... or one that does nothing at all with the data and just discards it.... or one that encrypts data... or one that compresses/zips it. The possibilities are endless.

This single 'MyOutput' function works with any kind of ostream... no matter what the ostream does with that data we give it. That's what abstraction is about. ostream is an abstract class that can be implemented any number of different ways.

Polymorphism is what makes this kind of abstraction possible.
Last edited on
Topic archived. No new replies allowed.