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.
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;.
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!
"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.
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!
Chapter 4
News Page
Lesson 1 contents
Contacting Me
Roby Joehanes © 2000