3

I'm watching tutorials from thenewboston on youtube ,and I have few questions about Polymorphism. Here is his code:

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


   protected:
   int attackPower;
public:
    void setAttackPower(int a){
    attackPower=a;
    }
};

class Ninja:public Enemy{
public:
    void attack(){
    cout<<"I am a ninja,ninja chop! -"<<attackPower<<endl;}
};

class Monster:public Enemy{
public:
void attack() {
cout<<"monnster must eat you!!! -"<<attackPower<<endl;
}
};

int main()
{
    Ninja n;
    Monster m;
    Enemy *enemy1=&n;
    Enemy *enemy2=&m;
    enemy1->setAttackPower(29);
    enemy2->setAttackPower(99);
    n.attack();
    m.attack();

}

My question is : Can I write the code in main() like this(or shouldn't I and WHY??):

Ninja n;
Monster m;
//Enemy *enemy1=&n;
//Enemy *enemy2=&m;
//enemy1->setAttackPower(29);
//enemy2->setAttackPower(99);
n.setAttackPower(99);
m.setAttackPower(29);
n.attack();
m.attack();
Rama
  • 3,222
  • 2
  • 11
  • 26
Sara.T
  • 41
  • 5
  • 2
    You can use references as well – P0W Jan 10 '17 at 12:09
  • 5
    Your example main isn't very representative. Dynamic polymorphism is useful when you *don't* know the type at compile time. It's hard to appreciate its power if you already know the actual types. – Kerrek SB Jan 10 '17 at 12:09
  • 6
    For polymorphism, you need `virtual` functions, besides having (and actually *using*) pointers to the base class. Try making `attack` a pure virtual function in the `Enemy` class, and use e.g. `enemy1->attack()` and `enemy2->attack()` instead. – Some programmer dude Jan 10 '17 at 12:10
  • 1
    There is no polymorphism in your examples, since there are no virtual functions. – Peter Jan 10 '17 at 12:16
  • @KerrekSB Valid point. To add a typical scenario for illustration: All enemies are held in a single vector with pointers to `Enemy`s (which can be any of the derived classes), which then, for example, all `attack()`. The using code (the loop over attacking Enemies) does not know and does not care what exact derived type each enemy is. To that code, all enemies behave the same. It is even possible to *add new types of enemies* in later iterations of the program *without changing or recompiling the code using enemies.* – Peter - Reinstate Monica Jan 10 '17 at 12:18
  • Or imagine that you read the enemies from a configuration file at runtime (e.g.: a level of a game)... – Karoly Horvath Jan 10 '17 at 12:27
  • 2
    That's possibly the least useful non-example I've seen - it doesn't involve any polymorphism whatsoever. You should find a better source than the "thenewboston", like investing in a [good book](http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). – molbdnilo Jan 10 '17 at 12:45
  • @molbdnilo True. I have a hard time understanding why anybody would watch TV (essentially) in order to learn how to program. – Peter - Reinstate Monica Jan 10 '17 at 12:57

3 Answers3

3

Can I write the code in main() like this [...]

Absolutely, you can! The reason for this is that your new example does not use polymorphic behavior. Unlike the original example, which hid the knowledge of run-time type of Enemy objects from compile-time code, your rewritten code keeps types available.

Here is what's not going to work without a pointer or a reference:

void setPowerAndAttack(Enemy enemy, int power) {
//                     ^^^^^^^^^^^
//  This is not going to work without pointer/reference
    enemy.setAttackPower(power);
    attack();
}
...
Ninja n;
Monster m;
setPowerAndAttack(n, 99);
setPowerAndAttack(m, 29);

Even though the code would compile, Enemy in setPowerAndAttack is not going to exhibit polymorphic behavior due to object slicing.

You need to make enemy a pointer or a reference to keep polymorphic behavior:

void setPowerAndAttack(Enemy& enemy, int power)
//                          ^

Very Important: You need to make attack function virtual in the Enemy class in order to have any polymorphic behavior at all. This is not clear from watching the video:

class Enemy {
protected:
   int attackPower;
public:
    void setAttackPower(int a) {
        attackPower=a;
    }
    virtual void attack();      // <<== Add this line
    virtual ~Enemy() = default; // <<== Add a virtual destructor
};
Community
  • 1
  • 1
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • 1
    Given the original post, it may not "go without saying" and the difference between a plain member function and a virtual one may warrant more explanation. – Peter - Reinstate Monica Jan 10 '17 at 12:21
  • @PeterA.Schneider I am pretty sure that OP has been a little sloppy copying the code from the video. [Here](http://stackoverflow.com/q/5931203/335858) is another question based on the same tutorial, and the `virtual` marker is there. – Sergey Kalinichenko Jan 10 '17 at 12:52
  • 1
    I just looked up the video and took a glance. It was quite painful to watch. I'm sorry to report that it is labeled "Introduction to polymorphism" without a virtual function in it. The OP copied the source code faithfully. Is it possible that you can have negative net information transfer wasting hundreds of kB/s? – Peter - Reinstate Monica Jan 10 '17 at 13:04
  • @PeterA.Schneider OMG, this is hard to believe indeed... Thank you for your comment, I added a longer note about `virtual`, and put a reference to Q&A explaining it in more detail. – Sergey Kalinichenko Jan 10 '17 at 13:15
2

Why do we use pointers with Polymorphism?

Because indirection is necessary to implement dymanic polymorphism. Pointers are a form of indirection, as are references which are also used for polymorphism.

Can I write the code in main() like this(or shouldn't I and WHY??):

You can, and you should. The shown class hierarchy in the is an example of non-polymorphic inheritance. The indirection adds nothing useful.

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

Your example is not using polymorphism.

Polymorphism could be simplified as providing different functionality via a common interface. Think USB devices: keyboard and flash-drive share the same USB port, but provide different functionality.

This example will use polymorphism:

#include <iostream>
using namespace std;
class Enemy
{
protected:
    int attackPower;

public:
    virtual ~Enemy() = default;
    virtual void attack() = 0;
    void setAttackPower(int a) { attackPower = a; }
};

class Ninja : public Enemy
{
public:
    void attack() 
    { 
        cout << "I am a ninja,ninja chop! -" << attackPower << endl; 
    }
};

class Monster : public Enemy
{
public:
    void attack() 
    { 
        cout << "monnster must eat you!!! -" << attackPower << endl; 
    }
};

int main()
{
    Ninja n;
    Monster m;
    Enemy* enemy1 = &n;
    Enemy* enemy2 = &m;
    enemy1->setAttackPower(29); // not polymorphism: interface and functionality are from Enemy
    enemy2->setAttackPower(99); // not polymorphism: interface and functionality are from Enemy
    enemy1->attack(); // polymorphism: interface of Enemy, functionality of Ninja
    enemy2->attack(); // polymorphism: interface of Enemy, functionality of Monster
}
AMA
  • 4,114
  • 18
  • 32