Thanks Bazzy and many others that help me to start understanding "polymorphism".
Below is a kind of skeleton to help join many things.
The idea is a base class that holds common code and common variables to derivatives classes. The scenario is thinking on a simple "shot game" with 2 guns (Gun1 and Gun2 classes) derivated from a base structure (GunBase class).
The idea is to help other beginners afraid "polymorphism" as I was.
Please indicate where this code should be improved.
// main.cpp
#include "gun1.h"
#include "gun2.h"
Gun1 g1;
Gun2 g2;
GunBase *ActiveGun;
int main()
{
ActiveGun=g1.Start(); // start with Gun1 but pass control to ActiveGun
cout << "You can run at " << ActiveGun->Speed() << endl;
ActiveGun->ExtraLoad();
ActiveGun=ActiveGun->Swap(&g1, &g2); // swap guns
cout << "Now you can run at " << ActiveGun->Speed() << endl;
ActiveGun->ExtraLoad();
ActiveGun=ActiveGun->Swap(&g1, &g2); // swap guns
cout << "Now you can run at " << ActiveGun->Speed() << endl;
return 0;
}
1 2 3 4 5 6 7 8 9 10 11 12
OUTPUT
code to load Gun1 1
You can run at 10
default ExtraLoad code
Gun1 Bye
code to load Gun2 2
Now you can run at 5
special Gun2 ExtraLoad code
Gun2 Bye
code to load Gun1 3
Now you can run at 10
// GunBase.h
#ifndef GUNBASE_H_
#define GUNBASE_H_
#include <iostream> // to std::cout
usingnamespace std;
class GunBase
{
public:
staticint total; // common variable to be used by all derivative classes
int weight; // variable available by each derivative class
//
//-------------------------------------
// Speed() is implemented ONLY here but uses Weight() that is implemented ONLY in
// derivative classes.
float Speed();
// So, Weight() must be declared here as pure virtual and be declared and implemented
// normally in each and ALL derivative classes.
virtualint Weight()=0;
//--------------------------------------
// Load() and UnLoad() are exposed by this class to main program, but are implemented
// ONLY in derivative classes, so they must be declared here as pure virtual class
// and be declared and implemented normally in each and all derivative classes.
virtualvoid Load()=0;
virtualvoid UnLoad()=0;
//--------------------------------------
// ExtraLoad() is exposed by this class to main program and has a "default"
// implementation here but also allows ANY derivative class to implement.
// In this case that implementation will be executed and not the "default".
virtualvoid ExtraLoad();
//------------------------------------
// Swap() is implemented ONLY here. Handle pointers
GunBase* Swap(GunBase*, GunBase*);
};
#endif /* GUNBASE_H_ */
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
// GunBase.cpp
#include "GunBase.h"
// just mandatory dummy initialization for static variables.
int GunBase::total = 0;
float GunBase::Speed(){return 100.0/Weight();}
void GunBase::ExtraLoad(){cout << "default ExtraLoad code" << endl;}
GunBase* GunBase::Swap(GunBase *p1, GunBase *p2)
{
if (this!=p1 and this!=p2) {return 0;} // something wrong
if (this==p2){GunBase* tempor=p2; p2=p1; p1=tempor;}
p1->UnLoad();
p2->Load();
return p2;
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
// gun1.h
#ifndef GUN1_H_
#define GUN1_H_
#ifndef GUNBASE_H_
#include "GunBase.h"
#endif
class Gun1 : public GunBase
{
public:
Gun1();
int Weight(); // must be here because pure virtual in base class
void Load(); // must be here because pure virtual in base class
void UnLoad(); // must be here because pure virtual in base class
GunBase* Start(); // only here. not in Gun2
};
#endif /* GUN1_H_ */
// gun2.h
#ifndef GUN2_H_
#define GUN2_H_
#ifndef GUNBASE_H_
#include "GunBase.h"
#endif
class Gun2 : public GunBase
{
public:
Gun2();
int Weight(); // must be here because pure virtual in base class
void Load(); // must be here because pure virtual in base class
void UnLoad(); // must be here because pure virtual in base class
void ExtraLoad(); // only here. not in Gun1
};
#endif /* GUN2_H_ */
Swap() change guns. It's called with the 2 guns in the example. It unloads the "active" gun and loads the other one and return the pointer for the other one.
The pointer for the active gun is stored in *ActiveGun variable, so you work indirectly with the "active gun" and not directly with gun1 or gun2.
Why GunBase() should have a virtual destructor ? (very interested to understand this part).
Weight() should be a const method ... assuming it will not change, right ?
I would rename Swap() to something else then. swap has a specific meaning in C++, which is why I was confused.
Without going into the details of why, the simple answer is that any time you have a base class with virtual functions or pure virtual functions it should also have a virtual destructor. The reason has to do with destroying objects through base class pointers. If you want more details, let me know.
Weight() simply returns the weight of the gun. The function itself does not change the object in any way. This is the sole criterion for making a member function const. (It does not matter whether the weight of the gun can change over time; it only matters whether the function itself can modify the object).