polymorphism example (beginners)

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.

Thank you
Regards
Marcio

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 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


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
// GunBase.h
#ifndef GUNBASE_H_
#define GUNBASE_H_
#include <iostream> // to std::cout
using namespace std;

class GunBase
{
	public:
		static int 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.
		virtual int 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.
		virtual void Load()=0;
		virtual void 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".
		virtual void 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_ */ 

1
2
3
4
5
6
7
8
// gun1.cpp
#include "gun1.h"

Gun1::Gun1(){weight=10;}
int Gun1::Weight(){return weight;}
void Gun1::Load(){cout<<"code to load Gun1 "<< ++total << endl;}
void Gun1::UnLoad(){cout<<"Gun1 Bye"<< endl;}
GunBase* Gun1::Start(){Load();return this;}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 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_ */ 

1
2
3
4
5
6
7
8
// gun2.cpp
#include "gun2.h"

Gun2::Gun2(){weight=20;}
int Gun2::Weight(){return weight;}
void Gun2::Load(){cout << "code to load Gun2 "  << ++total << endl;}
void Gun2::UnLoad(){cout << "Gun2 Bye" << endl;}
void Gun2::ExtraLoad(){cout << "special Gun2 ExtraLoad code"  << endl;}
Swap() does nothing useful. What do you want it to do?

GunBase() should have a virtual destructor.

Weight() should be a const method.

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).
Topic archived. No new replies allowed.