//Svaki konstruktor i svaki destruktor vrse ispis kako
//bi se ilustrovao redosled pozivanja konstruktora i destruktora

#include <iostream>

using namespace std;

//Klasa vozilo je apstraktna klasa iz koje izvodimo 
//sva ostala vozila
class Vozilo
{
    public:
        static int brojac; //Brojac koji broji broj kreiranih vozila

        Vozilo() //Konstruktor broji formirano vozilo
        {
        brojac++;
        cout<<"Vozilo() "<<brojac <<" ";
        }

        virtual ~Vozilo()    //Destruktor smanjuje broj vozila
        {
        brojac--;
        cout<<"~Vozilo() "
                << "brojac "
                << brojac<<endl;
        }

        //Virtuelne metode koje cemo predifinisati
        virtual int BrojPutnika() const = 0;
        virtual char* Naziv() const = 0;
        virtual int BrojTockova() const = 0;
        virtual bool ImaMotor() const =0; 

        //Omogucava ispis podataka o vozilu
        void Ispisi( ostream& ostr ) const
        {
        ostr << Naziv() 
 	        << " ima do " 
   	        << BrojPutnika() 
	        << " putnika. Broj tockova ovog vozila je "
	        << BrojTockova() <<". "<<endl
	        << "Ovo vozilo " << (ImaMotor() ? "ima" : "nema") << " motor." <<endl
	        << "Tenutan broj vozila je "
	        << brojac
	        << endl;
        }
};


//Bicikl predefinise odgovarajuce metode
class Bicikl : public Vozilo
{
    public:
        Bicikl() {cout << "Bicikl() "<<endl;}
        ~Bicikl() {cout << "~Bicikl() " ; }

        bool ImaMotor() const { return false;}
        int BrojPutnika() const { return 1; }
        char* Naziv() const { return "Bicikl"; }
        int BrojTockova() const {return 2;}
};


//Apstraktna klasa koja nasledjuje vozilo
class MotornoVozilo : public Vozilo
{
    public:
        MotornoVozilo() {cout<<"MotornoVozilo() ";}
        ~MotornoVozilo() {cout<<"~MotornoVozilo() ";}

        bool ImaMotor() const { return true;}
 };

//Kamion predefinise odgovarajuce metode
class Kamion : public MotornoVozilo
{
    public:
        Kamion() {cout << "Kamion() "<<endl;}
        ~Kamion() {cout << "~Kamion() " ; }

        int BrojPutnika() const { return 2; }
        char* Naziv() const { return "Kamion"; }
        int BrojTockova() const {return 16;}
};

//Automobil predefinise odgovarajuce metode
class Automobil : public MotornoVozilo
{
    public:
        Automobil() {cout << "Automobil() "<<endl;}
        ~Automobil() {cout << "~Automobil() " ; }

        int BrojPutnika() const { return 5; }
        char* Naziv() const { return "Automobil"; }
        int BrojTockova() const {return 4;}
};

//Autobus predefinise odgovarajuce metode
class Autobus : public MotornoVozilo
{
    public:
        Autobus() {cout << "Autobus() "<<endl;}
        ~Autobus() {cout << "~Autobus() " ; }

        int BrojPutnika() const { return 50; }
        char* Naziv() const { return "Autobus"; }
        int BrojTockova() const {return 8;}
};

//Kabriolet nasledjuje automobil, predefinise samo naziv!
class Kabriolet : public Automobil
{
    public:
        Kabriolet() {cout << "Kabriolet() "<<endl;}
        ~Kabriolet() {cout << "~Kabriolet() " ; }

        char* Naziv() const { return "Kabriolet"; }
};

//Funkcija koja vrsi ispis podataka o vozilu
void f( const Vozilo& v )
{
    cout << v.Naziv() 
            << " ima do " 
            << v.BrojPutnika() 
            << " putnika. Broj tockova ovog vozila je "
            << v.BrojTockova() <<". "<<endl
            << "Ovo vozilo " << (v.ImaMotor() ? "ima" : "nema") << " motor." <<endl
            << "Trenutno broj vozila je "
            << Vozilo::brojac
            << endl;
}

//Inicijalizacija staticke promenljive
int Vozilo::brojac=0;

//Ilustruje redosled pozivanja konstruktora, destruktora
//kao i pozivanje virtuelnih funkcija
main()
{
Vozilo* niz[10];
int i,n=0;
// niz[n++] = new Vozilo; ne moze jer je Vozilo apstraktna klasa
niz[n++] = new Automobil;
niz[n++] = new Autobus;
niz[n++] = new Kamion;
niz[n++] = new Bicikl;
niz[n++] = new Kabriolet;

for( i=0; i<n; i++ )
    niz[i]->Ispisi( cout );

for( i=0; i<n; i++ )
    f( *niz[i] );

for( i=0; i<n; i++ )
    delete niz[i]; 

return 0;
}

/* Izlaz iz programa:
Vozilo() 1 MotornoVozilo() Automobil()
Vozilo() 2 MotornoVozilo() Autobus()
Vozilo() 3 MotornoVozilo() Kamion()
Vozilo() 4 Bicikl()
Vozilo() 5 MotornoVozilo() Automobil()
Kabriolet()
Automobil ima do 5 putnika. Broj tockova ovog vozila je 4.
Ovo vozilo ima motor.
Tenutan broj vozila je 5
Autobus ima do 50 putnika. Broj tockova ovog vozila je 8.
Ovo vozilo ima motor.
Tenutan broj vozila je 5
Kamion ima do 2 putnika. Broj tockova ovog vozila je 16.
Ovo vozilo ima motor.
Tenutan broj vozila je 5
Bicikl ima do 1 putnika. Broj tockova ovog vozila je 2.
Ovo vozilo nema motor.
Tenutan broj vozila je 5
Kabriolet ima do 5 putnika. Broj tockova ovog vozila je 4.
Ovo vozilo ima motor.
Tenutan broj vozila je 5
Automobil ima do 5 putnika. Broj tockova ovog vozila je 4.
Ovo vozilo ima motor.
Trenutno broj vozila je 5
Autobus ima do 50 putnika. Broj tockova ovog vozila je 8.
Ovo vozilo ima motor.
Trenutno broj vozila je 5
Kamion ima do 2 putnika. Broj tockova ovog vozila je 16.
Ovo vozilo ima motor.
Trenutno broj vozila je 5
Bicikl ima do 1 putnika. Broj tockova ovog vozila je 2.
Ovo vozilo nema motor.
Trenutno broj vozila je 5
Kabriolet ima do 5 putnika. Broj tockova ovog vozila je 4.
Ovo vozilo ima motor.
Trenutno broj vozila je 5
~Automobil() ~MotornoVozilo() ~Vozilo() brojac 4
~Autobus() ~MotornoVozilo() ~Vozilo() brojac 3
~Kamion() ~MotornoVozilo() ~Vozilo() brojac 2
~Bicikl() ~Vozilo() brojac 1
~Kabriolet() ~Automobil() ~MotornoVozilo() ~Vozilo() brojac 0
*/
