A Twisted Look at Object Oriented Programming in C# By Jeff Louie 11/13/2002I must admit that my first exposure to object oriented programming (OOP) wasfrustrating and difficult. As a hobbyist I have struggled through Z80 assemblyand EPROM burners, BASIC, Turbo Pascal, Java, C++ COM and now C#. The move toevent driven programming and then to object oriented programming presented majorconceptual hurdles to my function driven sequential programming mindset. The “aha”moment when OOP made sense was most gratifying, but did not come quickly oreasily. It has been a few years since I “got” the OOP mindset and I feelcomfortable enough now to try to help fellow travelers with this journey. If OOPcomes easily to you, feel free to skip this tutorial. If you are having problemsgetting your mind around objects and inheritance I hope this tutorial can helpyou. This tutorial does not represent a conventional teaching method. It assumesa passing knowledge of the C# language and familiarity with the Visual Studio.NET IDE. This is a work in progress and may require correction orrevisions. Comments are actively requested (email: Jeff_Louie@yahoo.com). Useful Texts I highly recommend the following books. Much of my understanding of OOP hasbeen gleamed from these “classic” texts and then reinforced from codingdatabase projects in Java, C++ and C#. At all times I willfully try to avoidplagiarizing these authors, but my understanding of OOP is so closely tied tothese texts that I must cite them as sources of knowledge right from thestart! Object-Oriented Analysis and Design with Applications GradyBooch, Second Edition, Addison-Wesley, 1994, 589pp. Design Patterns Elements of Reusable Object-Oriented SoftwareGamma Helm, Johnson and Vlissides, Addison-Wesley, 1994, 395pp. Object-Oriented Software Construction Second Edition BertrandMeyer, Prentice Hall, 1997, 1254pp. Of course, some of this material is a descendent of my writing from our nowout of print book: Visual Café for Java Explorer Database Development EditionBrogden Louie and Tittle, Coriolis, 1998, 595pp. Chapter 8 "Shadow Fields, Override VirtualMethods" Well, I am going to finish this "nuts and bolts" chapter before I flame out! I promised thatI would discuss overriding, so I am going to make good on this promise. Ingeneral when you extend a class, you shadow fields with the same name in thebase class and override virtual methods with the same name and parameter list inthe base class. Overriding makes the base class method invisible. Shadowinga field, only hides the field from view. You can still explicitly touch thehidden shadowed field if you wish. You cannot touch an invisible overriddenmethod. To demonstrate the difference between shadowing and overriding I resort,as usual, to twisted code! First, you can create a sample base class with a public read only field"toastTime" and a virtual method "MakeToast()": class Base
{
public readonly int toastTime= 60;
public virtual void MakeToast()
{
System.Console.WriteLine("MakeToastInSeconds: "
+ toastTime.ToString());
}
}
Declaring the only method virtual explicitly allows a designer to overridethe MakeToast() method in a subclass. (Contrast this tothe approach in Java in which all methods are virtual by default.) This is important, since you areexplicitly allowing a subclass to completely rewrite the implementation of theMakeToast() method and in doing so make it totally invisible! Shadow Fields, Override Methods in the Base ClassNow you can extend or subclass the class Base: /// <summary>
/// Summary description for SubClass
/// </summary>
class SubClass : Base
{
public readonly new int toastTime= 1;
public override void MakeToast()
{
System.Console.WriteLine("MakeToastInMinutes: "
+ toastTime.ToString());
}
}
Note: You must explicitly tell the compiler that you are overriding thevirtual base class method MakeToast() with the key word overrideand that you are hiding the base field with the key word new.(You cannot override a field in a base class.) Overriding the method MakeToast makes the baseclass method with the same name and signature invisible to the caller of the class. This isin contrast to the base class field toastTime. The base class field toastTime is shadowed,but still potentially visible to the caller. You have shadowed a base class field and overridden a base class method. You can demonstrate the behavior of shadowed fields with the following test code: SubClass sc= new SubClass();
System.Console.WriteLine(sc.toastTime.ToString()); // --> 1
Base super= (Base)sc;
System.Console.WriteLine(super.toastTime.ToString()); // --> 60
In the above code snippet, the type of the reference variable determineswhich value of toastTime can be touched with the reference variable. Touchingthe field with a reference of type SubClass tells the compiler that you want totouch the the toastTime field of class SubClass. Casting thereference variable to the base type, tells the compiler that you want to touchthe toastTime field of the type Base. Both fields are potentially visible to thecaller. The base class field is shadowed, but still touchable. You can demonstrate the behavior of an overridden method with the followingtest code. This code demonstrates that the overridden base class method MakeToast isinvisible. You cannot touch the overridden method even if you cast the referenceto the base type. SubClass sc= new SubClass();
sc.MakeToast(); // --> MakeToastInMinutes: 1
Base super= (Base)sc;
super.MakeToast(); // --> MakeToastInMinutes: 1
Despite the cast, only the derived(specialized) classmethod is visible. If you think about it, this behavior is absolutely essential to polymorphism. Overriding insures that the"proper" implementation of a polymorphic method is called at runtime.You can demonstrate the proper polymorphic behavior with a little sample code. Here is yetanother version of the Drawable class, now with a default implementation ofDrawYourself. class Drawable
{
public virtual void DrawYourself()
{
System.Console.WriteLine("Drawable");
}
}
class Square : Drawable
{
public override void DrawYourself()
{
System.Console.WriteLine("Square");
}
}
class Circle : Drawable
{
public override void DrawYourself()
{
System.Console.WriteLine("Circle");
}
}
Here is the sample code that demonstrates that the "proper" implementationis called at runtime. Drawable draw= new Drawable();
draw.DrawYourself(); //--> Drawable
draw= new Square();
draw.DrawYourself(); //--> Square
draw= new Circle();
draw.DrawYourself(); //--> Circle
Overriding insures that the proper superclass implementation is always called at runtime. The magic of polymorphism issecure. You Can Hide a MethodFor completeness sake, I will mention that you can hide a virtualmethod using the key word new instead of the keyword override. Go ahead. Edit the previous codesample and replace the key word override with the key word new. This is the new behavior that breaks polymorphism: Drawable draw= new Drawable();
draw.DrawYourself(); //--> Drawable
draw= new Square();
draw.DrawYourself(); //--> Drawable
draw= new Circle();
draw.DrawYourself(); //--> Drawable
Perhaps not what you wanted! All Rights Reserved Jeff Louie 2002 |