/*
    Consistency is fundamental in class design and implementation.
        We can speak about external consistency (in the interface) and
        internal consistency (in the implementation of each objects state.

    When inheritance is used, there is a further issue of consistency
        to consider: consistency in the interface between a base class and
        its derived classes. In addition to the public interface, a base
        class may have a protected interface consisting of the protected
        members accessible from derived classes. By declaring protected
        members, a base class provides special access for use by its derived
        classes. The derived classes must use this access consistently with
        the implementation of the base class.

        Car and Truck make inconsistent use of the base protected member 
        plate. The default constructor of Vehicle set plate to 0 pointer.
        However identify() function in Car and Truck pass plate to printf
        vithout checking for a null value. If the parameter for %s is a 
        null value, the behaviour of printf is not defined.

    The following code has an undefined result:

        Truck t;
        t.identify();

 */

#include <stdio.h>
#include <string.h>

class Vehicle
{
public:
    Vehicle() { plate = 0; }
    Vehicle(char *p)
    {
        plate = new char[strlen(p)+1];
        strcpy(plate, p);
    }
   ~Vehicle() { delete [] plate; }
    virtual void identify()     { printf("generic vehicle\n"); }

protected:
    char   *plate;
};

/*
        The root of the problem is in the identify() member function 
        in the derived classes. They behave inconsistently with respect 
        to the protected interface of their base class. The base class
        represents a missing license plate number with a null pointer,
        but the derived identify() functions assume that the pointer is
        always non-null.

    A derived class cannot be coded before its base class. A derived
        class should conform consistently to the conventions established
        by its base class. In our example, the derived classes do not
        account for all of the legitimate states of the base part of their
        objects.

    To correct the bug, Car::identify() and Truck::identify() should
        test for null pointer and take a reasonable action to handle that 
        case.
 */

class Car : public Vehicle
{
public:
    Car() : Vehicle() { }
    Car(char *p) : Vehicle(p) { };
    void identify() 
        { 
                char *p = plate ? plate : "<node>";
                printf("car with plate %s\n", p); 
        }
};

class Truck : public Vehicle
{
public:
    Truck() : Vehicle() { }
    Truck(char *p) : Vehicle(p) { };
    void identify() 
        { 
                char *p = plate ? plate : "<node>";
                printf("truck with plate %s\n", p); 
        }
};

/*
        An other important point to see is, that Vehicle has a non-virtual
        destructor. We know, that for a polymorphic type a virtual destructor
        is very important. However, if the derived classes have no destructor
        defined, the non-virtual base destructor causes no problem.As long as
        the derived classes do not need destructors, the base class may remain
        as it is.

    (This rule does not adequately address multiply inheritance.)
 */

class Garage
{
public:
    Garage(int max);
   ~Garage();

    int       accept(Vehicle*);
    Vehicle  *release(int bay);
    void      listVehicles();
private:
    int       maxVehicles;
    Vehicle **parked;
};

Garage::Garage(int max)
{
    maxVehicles = max;
    parked = new Vehicle*[maxVehicles];
    for( int bay = 0; bay < maxVehicles; ++bay ) 
    {
        parked[bay] = 0;
    }
}

Garage::~Garage()
{
    delete [] parked;
}

int Garage::accept(Vehicle *veh)
{
    for( int bay = 0; bay < maxVehicles; ++bay )
        if( !parked[bay] )
        {
        parked[bay] = veh;
            return( bay );
        }
    return( -1 );       // No free bay
}

Vehicle *Garage::release(int bay)
{
    if( bay < 0 || bay > maxVehicles )
        return 0;
    Vehicle *veh = parked[bay];
    parked[bay] = 0;
    return( veh );
}

void    Garage::listVehicles()
{
    for( int bay = 0; bay < maxVehicles; ++bay )
        if( parked[bay] )
        {
        printf("Vehicle in bay %d is: ", bay);
            parked[bay]->identify();
        }
}

Car c1("AAA100");
Car c2("BBB200");
Car c3("CCC300");

Truck t1("TTT999");
Truck t2("SSS888");
Truck t3("UUU777");


int main( )
{
    Garage Park(14);

    Park.accept(&c1);
    int t2bay = Park.accept(&t2);
    Park.accept(&c3);
    Park.accept(&t2);

    Park.release(t2bay);

    Park.listVehicles();

    return 0;
}

/*
 
   The output of the program is the following:

Vehicle in bay 0 is: car with plate AAA100
Vehicle in bay 2 is: car with plate CCC300
Vehicle in bay 3 is: truck with plate SSS888

 */