Object Oriented Programming Philosophy

Part 3 -- Inheritance and Method Overloading




Welcome

Welcome back! Well, I've been busy for a long time. Now, I shall continue on the OOP lesson. It is about inheritance and method overloading. You'd better brush up the materials from the last lessons.

 

Inheritance

Classes can inherit the behaviors of other classes. The behavior I mentioned here means either methods or fields or both. Let's say there is a class A and class B. Class B inherits class A. Class B is therefore called the sub-class of class A. Similarly, class A is called the super-class of B.

What is the effect of inheritance anyway? Suppose class A has two methods -- foo and bar -- and three fields -- x, y, and z. If we declare class B to inherit class A, class B will automatically have foo, bar, x, y, and z altogether even though we do not declare them. The example below will show you.

type
   A = object
          private
             x, y, z: integer;
          public
             procedure foo(a: integer);
             function bar(b: integer):integer;
        end;
   B = object (A) { B inherits A }
          private
             p, q: integer;
             procedure doh;
        end;

Even though class B does not declare x, y, and z, it does have them since B inherits A. Class B also have the method foo and bar. However, class A won't have p, q, and doh. So, see the example below:

{ Suppose this is the main begin..end }
var
  myB : B;
  myA : A;
begin
  myB.foo(5); { legal }
  myA.doh;    { illegal }
  writeln(myB.bar(3)); { legal }
  myb.doh;     { legal }
  myA := myB;  { legal  (*) }
  myB := myA;  { illegal (**) }
end.

The first 9 lines should be clear. However, you may be slightly confused with (*) and (**). Since class B has all that class A have, therefore, it is perfectly legal to assign a variable of type B into A as (*) suggests. Because the reverse is not true, therefore (**) is not legal. You can always assign any instance of sub-classes into a variable of type of its super-class. Confused? Let's see some broader example.

Let's suppose that class B and class C are inherited from A. Class D is inherited from B, class E is inherited from C. The inheritance tree will look like this:

      A
     / \
    B   C
    |   |
    D   E

Suppose, we have a variable declaration like this:

var
  my_A : A;
  my_B : B;
  my_C : C;
  my_D : D;
  my_E : E;

myB := myD; is legal since D is a sub-class of B. Likewise myA := myE;. Although E is not a direct sub-class of A, E is a sub-class of C and C is a sub-class of A. Therefore E is still a descendant of A, so it's legal. However, myC := myA; is not legal. You cannot assign a children type into its parent type.

However, be forewarned though, if you do this: myA := myB;, you no longer be able to treat myA as myB. Even though the instance of myA is actually myB, you cannot do myA.doh;.

 

Benefit of Inheritance

Then, what is the benefit of inheritance? This important property will allow you to model something from common types to its more specific types. For example, for your graphic library, you may want to create objects: Circle, Triangle, and Square. All of them will have the method: put -- to put the object into new coordinates, getX to get the X coordinate, similarly getY, setColor to set its color, and draw to draw itself. Because put, getX, getY, and setColor behaves the same way for those objects, wouldn't it be nice to combine all those?

For this purpose, we would like to create the object Shape as their super-class. The object Shape will have all the common methods. So, now for Circle, Triangle, and Square, we need to only write the draw method, right? Circle, Triangle, and Square inherits those common methods. Hm... that's handy!

 

Protected Keyword

"You said that declaring things private means other classes are not allowed to share the data, right?" you said. Oh yes. I'm sorry that I forgot to tell you about the protected stuff. You already know what public and private is. Declaring things public means that we can share them, and by declaring them private, others are not allowed to share it even to their descendants. Then, how can we share things as I mentioned above then? By declaring them protected. Declaring things protected allow you to share things (methods and fields) to the object's descendants (either direct or indirect descendants). However, other objects (that is not a descendant), may not access those things. Neat huh?

So, let's look at code snippet above, the class A and B. If you want to share x and y, but not z into class B, then you may want to modify the code as follows:

type
   A = object
          private
             z: integer;
          protected
             x, y: integer;
          public
             procedure foo(a: integer);
             function bar(b: integer):integer;
        end;
   B = object (A) { B inherits A }
          private
             p, q: integer;
             procedure doh;
        end;

So, x and y are now inherited to B (and thus B can access it). However, z is not visible to B because it's private.

 

Method Overloading

One of the neat things of OOP features is called method overloading. That cool name is simply a term for redefining ancestors methods to suit the needs of the current class.  Suppose you have a class declaration Employee to model employees in a database system, then you also have a class ITStaff which is declared as a descendant of Employee. Suppose you have a method called getSalary in class Employee. Suppose you want to give a different salary rule for ITStaff. Let's say that the salary rule of regular employee is defined as follows: (Let's assume that the field workingHour, rate and overTimeRate is already defined in Employee class).

function Employee.getSalary: longint;
var
  result : longint;
begin
  result := workingHour * rate;
  if workingHour > 40 result := result + (workingHour - 40) * overTimeRate;
  getSalary := result;
end;

To give a different salary rule for ITStaff, you could just redefine getSalary method in class ITStaff. For example:

function ITStaff.getSalary: longint;
var
  result : longint;
begin
  { Suppose an ITStaff will always have $1000 more than ordinary employee }
  result := workingHour * rate + 1000;
  if workingHour > 40 result := result + (workingHour - 40) * overTimeRate;

  { They also receive bonus, assuming that bonus field is defined in class ITStaff }
  result := result + bonus;
  getSalary := result;
end;

See? Let's look at this example:

var
   ordEmployee : ^Employee;
   anITStaff   : ^ITStaff;
begin
  new(ordEmployee, init);
  new(anITStaff, init);
  :
  :
  writeln (ordEmployee^.getSalary);    { an ordinary employee's salary is printed out }
  writeln (ITStaff^.getSalary);    { an IT staff's salary is printed out }
  :
  :
  dispose(ordEmployee, done);
  dispose(anITStaff, done);
end.

I hope the example above clears out your doubt. I know that this is a bit fuzzy at the first time, but you'd understand after you practice sometime. You may have a lot of questions at this point. You have to clear it out before carrying into virtual methods in the next chapter. OK. See you!

 


Where to go

Chapter 4
News Page
Lesson 1 contents
Contacting Me


Roby Joehanes © 2000