8.6 Overriding the MethodsLet's add a mouse that can barely be heard : { package Animal; sub speak { my $class = shift; print "a $class goes ", $class->sound, "!\n"; } } { package Mouse; @ISA = qw(Animal); sub sound { "squeak" } sub speak { my $class = shift; print "a $class goes ", $class->sound, "!\n"; print "[but you can barely hear it!]\n"; } } Mouse->speak; which results in: a Mouse goes squeak! [but you can barely hear it!] Here, Mouse has its own speaking routine, so Mouse->speak doesn't immediately invoke Animal->speak . This is known as overriding . You use overriding to shadow the method in the derived class ( Mouse ) because you have a specialized version of the routine, instead of calling the more general base class's method (in Animal ). In fact, you didn't even need to initialize @Mouse::ISA to say that a Mouse was an Animal at all because all the methods needed for speak are defined completely with Mouse . You've now duplicated some of the code from Animal->speak ; this can be a maintenance headache . For example, suppose someone decides that the word goes in the output of the Animal class is a bug. Now the maintainer of that class changes goes to says . Your mice will still say goes , which means the code still has the bug. The problem is that you invoked cut and paste to duplicate code, and in OOP, that is a sin. You should reuse code through inheritance, not by cut and paste. How can you avoid that? Can you say somehow that a Mouse does everything any other Animal does, but add in the extra comment? Sure! As your first attempt, you can invoke the Animal::speak method directly: { package Animal; sub speak { my $class = shift; print "a $class goes ", $class->sound, "!\n"; } } { package Mouse; @ISA = qw(Animal); sub sound { "squeak" } sub speak { my $class = shift; Animal::speak($class); print "[but you can barely hear it!]\n"; } } Note that because you've stopped using the method arrow, you have to include the $class parameter (almost surely the value of " Mouse ") as the first parameter to Animal::speak ,. Why did you stop using the arrow? Well, if you invoke Animal->speak there, the first parameter to the method is " Animal, " not " Mouse ", and when the time comes for it to call for the sound , it won't have the right class to select the proper methods for this object. Invoking Animal::speak directly is a mess, however. What if Animal::speak didn't exist before and was inherited from a class mentioned in @Animal::ISA ? For example, suppose the code was: { package LivingCreature; sub speak { ... } ... } { package Animal; @ISA = qw(LivingCreature); # no definition for speak( ) ... } { package Mouse; @ISA = qw(Animal); sub speak { ... Animal::speak( ... ); } ... } Because you no longer use the method arrow, you get one and only one chance to hit the right subroutine. You'll look for it in Animal , and not find it, and the program aborts. The Animal classname is now hardwired into the subroutine selection. This is a mess if someone maintains the code, changing @ISA for Mouse , and didn't notice Animal there in speak . Thus, this is probably not the right way to go. |