WittyGuy said:
Hi all,
Though I know the concepts of both abstract class & virtual
function (like derived class pointer pointing to base class...then
calling the function with the pointer...), what is the real
implementation usage of these concepts? Where these concepts will be
used. Please provide some illustration (real-time), so that it can be
easily comprehended.
Thanks,
wittyGuy
Take a look around you, find me an object which you couldn't classify. In
reality, the whole world around you is classified in some way. Life and
genes, elements and materials, businesses and products, date and time,
energy and work, etc.
The basic idea is that you can classify (no pun intended), contain, upcast,
or provide easy code-expansion for a new object based on its provided
derivative(s).
Common example
A Shape class can be an abstract class to derive a Triangle class, a
Rectangle class and a Circle class. A pure-virtual getArea() member function
in the abstract Shape class requires you to define the getArea() member
function in each of its derivatives. The Circle and the Rectangle, for
example, don't rely on the same getArea() member function to calculate its
area.
Note that this makes OO sense since:
A Triangle is_a Shape
A Rectangle is_a Shape
A Circle is_a Shape
Containers
The benefit is now you can use a container that holds any Shape (an array of
Shapes, a vector, a list, stack, queue, etc). The container needs not track
which shape element is a circle, a triangle or a rectangle. The Shape
container needs only satisfy that each element is a pointer to an existing
Shape derivative.
Shapes* shapes[4]; // a container of pointers to Shape objects
shapes[0] = new Rectangle(10, 10); // (width, length)
shapes[1] = new Circle(5); // (radius)
shapes[2] = new Triangle(7, 6) // (width, length)
shapes[3] = new Circle(22); // (radius)
The element at shapes[0] knows whether its a Circle, Rectangle or Triangle.
The same goes with every other element. The container doesn't care whether
Array[2] is a Triangle, a Rectangle or a Circle. So when you write:
int n = 0;
while ( n < 4 )
{
Array[n++]->getArea();
}
delete [] shapes;
You are calling the appropriate getArea() behaviour for each Shape-type
element in the container (using a vtable). This would not be possible
without the abstract Shape class (a container of what?). Neither would this
be possible without a pure-virtual getArea() member function in Shape (we
need to guarentee that all Shapes have such a member function available).
This ability to contain any derivative-type can be applied to Animals,
Vehicles, Employees, Airplanes, Planets or any other base class you can
think of. Note that the hierarchy need not be so shallow. A Car is a
derivative of Vehicle, a Sportscar is a derivative of Car, hence a Sportscar
can also be an element in a container of Vehicles.
Whats the benefit? All such Vehicles have an engine, a steering wheel and a
gas tank. There is no need to repeatedly insert an engine in all the derived
classes. A Vehicle base class can be composed of an engine and each derived
class needs only invoke the appropriate engine ctor to equip itself with a
particular engine. The startEngine() member function in Vehicle can now
start the engine in any Vehicle. This can save an enormous amount of code
when you consider the variety of motorized vehicle-types out there.
Should a client programmer choose to employ your classes (expand Shape to
provide a pentagon or octagon - expand Vehicle to provide a FireTruck), his
job has been made much easier for both you, the creator, and the client.
You've used a common abstract base class and pure-virtual member functions
which dictates and guarentees the implementation of the new derived entity
in the program.
A quick scan by the client of your base class permits him or her to draw up
the derived FireTruck. The client can add the water pump, the ladder, valves
and whatever he likes or needs. Yet that FireTruck can still be held in any
Vehicle container (highway, FireHouse, bridge, Ferry, Tunnel, etc) and the
original startEngine() member function still works.
The same principles of simplified code reusability can be applied in
virtually any appropriate classification hierarchy.