Go4Expert (http://www.go4expert.com/)
-   C++ (http://www.go4expert.com/forums/cpp/)
-   -   Polymorphism (http://www.go4expert.com/forums/polymorphism-t26985/)

 tonydav43 21Oct2011 09:22

Polymorphism

I am part way through a course, and we have just finished overloading a printstats game example. It then says this is not an ideal method, and polymorphism is better. Thing is, even though it talks about polymorphism, it does not give you a working example for the console output game we created. I have read almost every article on google, and still cannot get my head around polymorphism. Could someone please amend the code below, so the stats are printed out using polymorphism. The Vector3.h, and Vector3.cpp, are old reusable codes. I need it to also print out the number of missles the fighter ship has. There is alot more classes involved, but I have reduced the code for brevity. I just think that if I can see polymorphism working on this, I might get a better understanding of it. This is not a project, this is something I am working on.
Code:

```// Vector3.h #ifndef VECTOR3_H #define VECTOR3_H #include <iostream> class Vector3 { public:         Vector3();         Vector3(float coords[3]);         Vector3(float x, float y, float z);         bool equals(const Vector3& rhs);         Vector3 add(const Vector3& rhs);         Vector3 sub(const Vector3& rhs);         Vector3 mul(float scaler);         float length();         void normalize();         float dot(const Vector3& rhs);         float* toFloatArray();         void print();         void input();         float mX;         float mY;         float mZ; }; #endif```
Code:

```/ Vector3.cpp #include <iostream> #include <cmath> #include "Vector3.h" using namespace std;         Vector3::Vector3()         {         mX = 0.0f;         mY = 0.0f;         mZ = 0.0f;         }                 Vector3::Vector3(float coords[3])         {         mX = coords[0];         mY = coords[1];         mZ = coords[2];         }                 Vector3::Vector3(float x, float y, float z)         {         mX = x;         mY = y;         mZ = z;         }                 bool Vector3::equals(const Vector3& rhs)         {         return         mX == rhs.mX &&         mY == rhs.mY &&         mZ == rhs.mZ;         }                 Vector3 Vector3::add(const Vector3& rhs)         {         Vector3 sum;         sum.mX = mX + rhs.mX;         sum.mY = mY + rhs.mY;         sum.mZ = mZ + rhs.mZ;         return sum;         }                 Vector3 Vector3::sub(const Vector3& rhs)         {         Vector3 dif;         dif.mX = mX - rhs.mX;         dif.mY = mY - rhs.mY;         dif.mZ = mZ - rhs.mZ;         return dif;         }                 Vector3 Vector3::mul(float scaler)         {         Vector3 p;         p.mX = mX * scaler;         p.mY = mY * scaler;         p.mZ = mZ * scaler;         return p;         }                 float Vector3::length()         {         return sqrtf(mX*mX + mY*mY + mZ*mZ);         }                 void Vector3::normalize()         {         float len = length();         mX /= len;         mY /= len;         mZ /= len;         }                 float Vector3::dot(const Vector3& rhs)         {         float dotP = mX*rhs.mX + mY*rhs.mY + mZ*rhs.mZ;         return dotP;         }                 float* Vector3::toFloatArray()         {         return &mX;         }                 void Vector3::print()         {         cout << "<" << mX << ", " << mY << ", " << mZ << "> \n";         }                 void Vector3::input()         {         cout << "Enter x: ";         cin >> mX;         cout << "Enter y: ";         cin >> mY;         cout << "Enter z: ";         cin >> mZ;         }```
Code:

```// Spaceship.h #ifndef SPACESHIP_H #define SPACESHIP_H #include <iostream> #include <string> #include "Vector3.h" using namespace std; class Spaceship { public:         Spaceship();         Spaceship(                 const string& name,                 const Vector3& pos,                 const Vector3& vel,                 int fuel,                 int damage);         void landed();         void attacking();         void printStats(); protected:         string mName;         Vector3 mPosition;         Vector3 mVelocity;         int mFuelLevel;         int mDamage; }; class HumanShip : public Spaceship { public:         HumanShip(                 const string& name,                 const Vector3& pos,                 const Vector3& vel,                 int fuel,                 int damage);                 }; class HumanFighterShip : public HumanShip { public:         HumanFighterShip(                 const string& name,                 const Vector3& pos,                 const Vector3& vel,                 int fuel,                 int damage,                 int numMissles);                 void fireLaserGun();                 void fireMissle();                 private:                 int mNumMissles; }; #endif```
Code:

```// Spaceship.cpp #include "Spaceship.h" #include <iostream> #include "Vector3.h" using namespace std; Spaceship::Spaceship() {         mName                        = "DefaultName";         mPosition                = Vector3(0.0f, 0.0f, 0.0f);         mVelocity                = Vector3(0.0f, 0.0f, 0.0f);         mFuelLevel                = 100;         mDamage                        = 0;         } Spaceship::Spaceship(const string& name,                                         const Vector3& pos,                                         const Vector3& vel,                                         int fuel,                                         int damage) {         mName                        = name;         mPosition                = pos;         mVelocity                = vel;         mFuelLevel                = fuel;         mDamage                        = damage;         } HumanShip::HumanShip(const string& name,                                         const Vector3& pos,                                         const Vector3& vel,                                         int fuel,                                         int damage) {         mName                        = name;         mPosition                = pos;         mVelocity                = vel;         mFuelLevel                = fuel;         mDamage                        = damage;         } void Spaceship::landed() {         cout << mName <<" has landed" << endl; } void Spaceship::attacking() {         cout << mName << " is attacking" << endl; } void Spaceship::printStats() {         cout << "Name = " << mName << endl;         cout << "Position = <";          cout << mPosition.mX << ", ";         cout << mPosition.mY << ", ";         cout << mPosition.mZ << ">" << endl;         cout << "Velocity = <";         cout << mVelocity.mX << ", ";         cout << mVelocity.mY << ", ";         cout << mVelocity.mZ << ">" << endl;         cout << "Fuel Level = " << mFuelLevel << endl;         cout << "Damage = " << mDamage << endl;         } HumanFighterShip::HumanFighterShip(const string& name,                                                 const Vector3& pos,                                                 const Vector3& vel,                                                 int fuel,                                                 int damage,                                                 int numMissles) :HumanShip(name,pos, vel, fuel, damage) {         mNumMissles = numMissles; } void HumanFighterShip::fireLaserGun() {         cout << "Firing " << mName << " laser guns." << endl; } void HumanFighterShip::fireMissle() {         if(mNumMissles > 0)         {                 cout << "Firing " << mName << " missles." << endl;                 mNumMissles--;         }         else                 cout << "Out of missles." << endl; }```
Code:

```// Main.cpp #include <iostream> #include "SpaceShip.h" #include "Vector3.h" using namespace std; int main() {         HumanFighterShip fighter("Human Fighter", Vector3(5.0f, 6.0f, -3.0f),                 Vector3(1.0f, 2.0f, 3.0f),100, 0, 10);                         fighter.printStats();                 cout << endl;         fighter.attacking();         fighter.fireLaserGun();         fighter.fireMissle(); }```

 xpi0t0s 22Oct2011 04:50

Re: Polymorphism

You need a few more things before polymorphism can work here.
- HumanFighterShip and HumanShip need an implementation of printStats()
- an array containing a number of HumanFighterShips and HumanShips. This array should be defined as an array of SpaceShips, e.g. SpaceShip *arr[10]; Assigning one of those two to an array entry works fine, even though the types are technically different. For example:
Code:

`arr[0]=new HumanFighterShip();`
- possibly some HumanFighterShip- and HumanShip- specific attributes for HumanFighterShip:: printStats() and HumanShip:: printStats() to access - so that you know it's using those two functions and not SpaceShip:: printStats() (spaces added to stop : p displaying as :p )

Then polymorphism can be demonstrated easily with:
Code:

```for (int i=0; i<10; i++) {   arr[i]->printStats(); }```

 tonydav43 22Oct2011 05:17

Re: Polymorphism

Hi Thanks for the reply. I only have 1 instance of human fighter ship at present, but I understand what you are saying about the array. I have re-wittne the code as follows, and any comments would be appreciated. The code runs fine and prints to console all the stats including the additional humanfightership missile stat:
Code:

``` // Main.cpp #include <iostream> #include "SpaceShip.h" #include "Vector3.h" using namespace std; int main() {     Spaceship* ship = new HumanFighterShip("Human Fighter", Vector3(5.0f, 6.0f, -3.0f), Vector3(1.0f, 2.0f, 3.0f),100, 0, 10);     ship->printStats();     cout << endl;     HumanFighterShip* fighterShip = (HumanFighterShip*) ship;     fighterShip->attacking();     fighterShip->fireLaserGun();     fighterShip->fireMissle();       delete ship; }```
Code:

``` // Spaceship.cpp #include "Spaceship.h" #include <iostream> #include "Vector3.h" using namespace std; Spaceship::Spaceship() {         mName                        = "DefaultName";         mPosition                = Vector3(0.0f, 0.0f, 0.0f);         mVelocity                = Vector3(0.0f, 0.0f, 0.0f);         mFuelLevel                = 100;         mDamage                        = 0;         } Spaceship::Spaceship(const string& name,                                         const Vector3& pos,                                         const Vector3& vel,                                         int fuel,                                         int damage) {         mName                        = name;         mPosition                = pos;         mVelocity                = vel;         mFuelLevel                = fuel;         mDamage                        = damage;         } HumanShip::HumanShip(const string& name,                                         const Vector3& pos,                                         const Vector3& vel,                                         int fuel,                                         int damage) {         mName                        = name;         mPosition                = pos;         mVelocity                = vel;         mFuelLevel                = fuel;         mDamage                        = damage;         } void Spaceship::landed() {         cout << mName <<" has landed" << endl; } void Spaceship::attacking() {         cout << mName << " is attacking" << endl; } void Spaceship::printStats() {         cout << "Name = " << mName << endl;         cout << "Position = <";          cout << mPosition.mX << ", ";         cout << mPosition.mY << ", ";         cout << mPosition.mZ << ">" << endl;         cout << "Velocity = <";         cout << mVelocity.mX << ", ";         cout << mVelocity.mY << ", ";         cout << mVelocity.mZ << ">" << endl;         cout << "Fuel Level = " << mFuelLevel << endl;         cout << "Damage = " << mDamage << endl;         } void HumanFighterShip::printStats() {         Spaceship::printStats();         cout << "Missles = " << mNumMissles << endl; } HumanFighterShip::HumanFighterShip(const string& name,                                                 const Vector3& pos,                                                 const Vector3& vel,                                                 int fuel,                                                 int damage,                                                 int numMissles) :HumanShip(name,pos, vel, fuel, damage) {         mNumMissles = numMissles; } void HumanFighterShip::fireLaserGun() {         cout << "Firing " << mName << " laser guns." << endl; } void HumanFighterShip::fireMissle() {         if(mNumMissles > 0)         {                 cout << "Firing " << mName << " missles." << endl;                 mNumMissles--;         }         else                 cout << "Out of missles." << endl; }```
Code:

```// Spaceship.h #ifndef SPACESHIP_H #define SPACESHIP_H #include <iostream> #include <string> #include "Vector3.h" using namespace std; class Spaceship { public:         Spaceship();         Spaceship(                 const string& name,                 const Vector3& pos,                 const Vector3& vel,                 int fuel,                 int damage);         void landed();         void attacking();         virtual void printStats(); protected:         string mName;         Vector3 mPosition;         Vector3 mVelocity;         int mFuelLevel;         int mDamage; }; class HumanShip : public Spaceship { public:         HumanShip(                 const string& name,                 const Vector3& pos,                 const Vector3& vel,                 int fuel,                 int damage);                         }; class HumanFighterShip : public HumanShip { public:         HumanFighterShip(                 const string& name,                 const Vector3& pos,                 const Vector3& vel,                 int fuel,                 int damage,                 int numMissles);                 void fireLaserGun();                 void fireMissle();                 void printStats();                                                 private:                 int mNumMissles; }; #endif```
I am sure that I am now using polymorphism, but correct me if I am wrong

 xpi0t0s 22Oct2011 05:41

Re: Polymorphism

Yes, you are now using it. It's "more satisfying" though to do what I suggested and manage a bunch of Human*Ships using a collection of pointers to SpaceShips, but it's not necessary.

 tonydav43 23Oct2011 16:19

Re: Polymorphism

I have got the code to work using polymorphism, so I thought I would give an array of human fighter ships a go. The code complies, prints then says test.exe has stopped working, and I cannot figure out why. Can you see anything from the code below?
Code:

```// Spaceship.h #ifndef SPACESHIP_H #define SPACESHIP_H #include <iostream> #include <string> #include "Vector3.h" using namespace std; class Spaceship { public:         Spaceship();         Spaceship(                 const string& name,                 const Vector3& pos,                 const Vector3& vel,                 int fuel,                 int damage);         virtual void printStats(); protected:         string mName;         Vector3 mPosition;         Vector3 mVelocity;         int mFuelLevel;         int mDamage; }; class HumanShip : public Spaceship { public:         HumanShip(                 const string& name,                 const Vector3& pos,                 const Vector3& vel,                 int fuel,                 int damage); }; class HumanFighterShip : public HumanShip { public:         HumanFighterShip(                 const string& name,                 const Vector3& pos,                 const Vector3& vel,                 int fuel,                 int damage,                 int type,                 int numMissles);                 void printStats(); private:                 int mType;                 int mNumMissles; }; #endif```
Code:

``` // Main.cpp #include <iostream> #include "SpaceShip.h" #include "Vector3.h" using namespace std; int main() {             Spaceship* fighterHuman[5];                 fighterHuman[0] = new HumanFighterShip("Human Fighter Class 1", Vector3(5.0f, 6.0f, -3.0f),                 Vector3(1.0f, 2.0f, 3.0f),100, 0, 1, 10);         fighterHuman[1] = new HumanFighterShip("Human Fighter Class 2", Vector3(5.0f, 6.0f, -3.0f),                 Vector3(1.0f, 2.0f, 3.0f),100, 0, 2, 10);         fighterHuman[2] = new HumanFighterShip("Human Fighter Class 3", Vector3(5.0f, 6.0f, -3.0f),                 Vector3(1.0f, 2.0f, 3.0f),100, 0, 3, 10);         fighterHuman[3] = new HumanFighterShip("Human Fighter Class 4", Vector3(5.0f, 6.0f, -3.0f),                 Vector3(1.0f, 2.0f, 3.0f),100, 0, 4, 10);         fighterHuman[4] = new HumanFighterShip("Human Fighter Class 5", Vector3(5.0f, 6.0f, -3.0f),                 Vector3(1.0f, 2.0f, 3.0f),100, 0, 5, 10);         for(int i = 0; i < 5; ++i)         {             fighterHuman[i]->printStats();         cout << endl;         }         for(int i = 0; 1 < 5; ++i)         {         delete fighterHuman[i];         } }```
Code:

``` // Spaceship.cpp #include "Spaceship.h" #include <iostream> #include "Vector3.h" using namespace std; Spaceship::Spaceship() {         mName                        = "DefaultName";         mPosition                = Vector3(0.0f, 0.0f, 0.0f);         mVelocity                = Vector3(0.0f, 0.0f, 0.0f);         mFuelLevel                = 100;         mDamage                        = 0;         } Spaceship::Spaceship(const string& name,                                         const Vector3& pos,                                         const Vector3& vel,                                         int fuel,                                         int damage) {         mName                        = name;         mPosition                = pos;         mVelocity                = vel;         mFuelLevel                = fuel;         mDamage                        = damage;         } HumanShip::HumanShip(const string& name,                                         const Vector3& pos,                                         const Vector3& vel,                                         int fuel,                                         int damage) {         mName                        = name;         mPosition                = pos;         mVelocity                = vel;         mFuelLevel                = fuel;         mDamage                        = damage;         } void Spaceship::printStats() {         cout << "Name = " << mName << endl;         cout << "Position = <";          cout << mPosition.mX << ", ";         cout << mPosition.mY << ", ";         cout << mPosition.mZ << ">" << endl;         cout << "Velocity = <";         cout << mVelocity.mX << ", ";         cout << mVelocity.mY << ", ";         cout << mVelocity.mZ << ">" << endl;         cout << "Fuel Level = " << mFuelLevel << endl;         cout << "Damage = " << mDamage << endl;         } void HumanFighterShip::printStats() {         Spaceship::printStats();         cout << "Fighter Class = " << mType << endl;         cout << "Missles = " << mNumMissles << endl; } HumanFighterShip::HumanFighterShip(const string& name,                                                 const Vector3& pos,                                                 const Vector3& vel,                                                 int fuel,                                                 int damage,                                                 int type,                                                 int numMissles) :HumanShip(name,pos, vel, fuel, damage) {         mType = type;         mNumMissles = numMissles; }```
I have not included the Vector3.h and cpp file

 tonydav43 23Oct2011 17:17

Re: Polymorphism

Sorted the problem

Code:

```for(int i = 0; i < 5; ++i)         {             fighterHuman[i]->printStats();         cout << endl;         }         for(int i = 0; 1 < 5; ++i) // Should be i < 5         {         delete fighterHuman[i];         }```

 xpi0t0s 24Oct2011 01:44

Re: Polymorphism

Interesting. Did you get any warnings from the compiler, such as "condition is always true"?

If not, try switching warnings to the maximum level, recompile the program with the error still in it, and see what it tells you. Warnings can be a good place to start looking for the reason for unexplained crashes.

I tried to spot the error in the code but I missed it. 1 looks too much like i. There should be a lesson for you here regarding choice of variable names. Well done for spotting the error yourself though. Debugging is probably 90% of programming - certainly over half - and too many people post here going "it crashes, find it for me, waaah" without realising they're throwing away half the "fun" of programming.

 tonydav43 24Oct2011 14:38

Re: Polymorphism

Quote:
 Originally Posted by xpi0t0s (Post 88348) Interesting. Did you get any warnings from the compiler, such as "condition is always true"?
No did not get warning, and will change the warning level.

Have another question using arrays. I have objects in HumanFighterShip, which are not objects of Spaceship, which are fire laser and fire missiles. The code (snippet) I have at present is as follows:
Code:

```int main() {             HumanFighterShip* fighterHuman[3];                 fighterHuman[0] = new HumanFighterShip("Human Fightership Class 1", Vector3(5.0f, 6.0f, -3.0f),                 Vector3(1.0f, 2.0f, 3.0f),100, 0, 1, 100);         fighterHuman[1] = new HumanFighterShip("Human Fightership Class 2", Vector3(5.0f, 6.0f, -3.0f),                 Vector3(1.0f, 2.0f, 3.0f),100, 0, 2, 110);         fighterHuman[2] = new HumanFighterShip("Human Fightership Class 3", Vector3(5.0f, 6.0f, -3.0f),                 Vector3(1.0f, 2.0f, 3.0f),100, 0, 3, 120);         for(int i = 0; i < 3; ++i)         {     fighterHuman[i]->attacking();         fighterHuman[i]->fireLaserGun();     fighterHuman[i]->fireMissle();         fighterHuman[i]->printStats();         cout << endl;         } for(int i = 0; i < 3; ++i)         {         delete fighterHuman[i];         }```
Code:

```//Spaceship.cpp void HumanFighterShip::fireLaserGun() {                 cout << "Firing " << mName << " laser guns." << endl; } void HumanFighterShip::fireMissle() {                 if(mNumMissles > 0)         {                 cout << "Firing " << mName << " missles." << endl;                 mNumMissles--;         }         else                 cout << "Out of missles." << endl; }```
Question is, if I change the following piece of code:
Code:

``` HumanFighterShip* fighterHuman[3]; to Spaceship* fighterHuman[3];```
it tells me that the 2 objects mentioned are not members of Spaceship. I might be barking up the wrong tree, but should you not use a pointer to the base class, or would that be wrong? If it is and if you dont mind, could you explain why

 xpi0t0s 24Oct2011 17:40

Re: Polymorphism

Polymorphism works when you can do everything you want to every object through the interface defined in the base class. Once you start trying to use functionality not defined at the base level, you have to leave it behind, decide what kind of object it is then start doing class-specific stuff, which by definition is not polymorphic.