next up previous
Next: Big Integer Up: Vehicles and Garages Previous: 3rd version (Coupling)

Final version (Value versus behaviour)

Vehicle::identify() was a virtual function in the original version of the program, and following that style group() is virtual in the revised version. Is a virtual function is the right way to capture the difference between the characteristic strings "car" and "truck"? The difference between the derived classes is one of value and not behaviour. Objects ofthe derived classes do not behave differently nor use different algorithms. A difference in value can be recorded more naturally in a data member than in a virtual function. A data member in Vehicle would be sufficient:

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

class Vehicle
{
public:
    // Vehicle(char *g) { group = g; plate = 0; }
    Vehicle(char *g, char *p)
    {
	group = g;
        plate = new char[strlen(p)+1];
        strcpy(plate, p);
    }
    virtual ~Vehicle() = 0;  // pure virtual 
    void identify()	
    { 
	char *p = plate ? plate : "none";
	printf( "%s with plate %s\n", group, p);
    }

private:
    char   *plate;
    char   *group;
};

The data member can receive its value from an additional argument to each Vehicle constructor, supplied by the corresponding derived constructor. The base and the derived classes interact only during initialization, further reducing coupling.

Vehicle::~Vehicle()
{ 
    delete [] plate; 
}

class Car : public Vehicle
{
public:
    // Car() : Vehicle("car") { }
    Car(char *p = 0) : Vehicle("car", p) { };
};

class Truck : public Vehicle
{
public:
    // Truck() : Vehicle("truck") { }
    Truck(char *p = 0) : Vehicle("truck", p) { };
};

We can further reduce the code by using default argument in the constructors of the derived classes and so eliminating the second cosntructors both in derived and the base classes.

In the same time we must mentioned that when we eliminated a virtual function we increased the size of the object. So the data versus function tradeoff has a size versus runtime parallel. Here we should recognize, that eliminating the virtual function also eliminated the vptr, se reduced size.

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;
}


next up previous
Next: Big Integer Up: Vehicles and Garages Previous: 3rd version (Coupling)
Porkoláb Zoltán 2001-09-03