1. Tech

Your suggestion is on its way!

An email with a link to:

http://delphi.about.com/library/bluc/text/uc061102i.htm

was emailed to:

Thanks for sharing About.com with others!

RTL referenceGlossary|Tips/Tricks|FREE App/VCL|Best'O'Net|Books|Link To
 
Creating Custom Delphi Components - Inside and Out
Page 9: Virtual functions and Abstract Classes
 More of this Feature
• Page 1: About components
• Page 2: New...Component
• Page 3: On Fields
• Page 4: On Properties
• Page 5: On Constructors
• Page 6: On Destructors and Methods
• Page 7: On Events
• Page 8: Hiding data
 Join the Discussion
"Post your views, comments, questions and doubts to this article."
Discuss!
 Related Resources
• VCL Writing/Enhancing
• Custom Component Dev.
• OOP in Delphi
• Free Source Components

   Virtual Functions
Virtual functions allow a great feature of object-oriented design: "Polymorphism". This is given a scary name because the Object-Oriented Design gurus are like that (why? Maybe they're scared people will break into their racket ;-). Sometimes I wonder about all this daft jargon).

If I had code like this:

type
  TMyShape = class
  public
    procedure Draw(x,y: Integer);
  end;

  TCircle = class(TMyShape)
  public
    procedure Draw(x,y: Integer);
  end;

  TRectangle = class(TMyShape)
  public
    procedure Draw(x,y: Integer);
  end;

// and later on
procedure DoSomething(Shape: TMyShape; x,y: Integer);
begin
  Shape.Draw(x,y);
end;

then DoSomething would execute TMyShape.Draw regardless of what was passed in. If a TCircle was passed in this would still be the case, and we wouldn't get a circle drawn. Clearly this isn't what we want to do - we want to execute the appropriate Draw procedure depending on what object was passed in, not the base class version! This is exactly where virtual methods come in.

When you declare a method as virtual you are saying to the compiler "I want you to call the appropriate derived version of this, not mine!" This means that you have an object declared as the base class and it magically calls the correct derived methods. This feature is very nifty and can be exceptionally useful in reducing code size or making your code very extensible.

To use virtual methods, add the "virtual" keyword after the method declaration. When you write sub-class versions of the procedure, remember the "override" part (a-ha! Now you finally know what that keyword is for!). Here's the previous example updated:

type
  TMyShape = class
  public
    procedure Draw(x,y: Integer); virtual;
  end;

  TCircle = class(TMyShape)
  public
    procedure Draw(x,y: Integer); override;
  end;

  TRectangle = class(TMyShape)
  public
    procedure Draw(x,y: Integer); override;
  end;

// and later on
procedure DoSomething(Shape: TMyShape; x,y: Integer);
begin
  Shape.Draw(x,y);
end;

Now the correct method gets called depending on what shape gets passed in. Very neat and tidy, isn't it? Remember that you might want to use the "inherited" keyword if your base class does useful stuff.

   Abstract Classes
The very final thing to discuss is abstract classes. These are classes you cannot create. Huh? What's the point then? Well, one thing inheritance is good for is getting rid of redundancy. It also allows you to introduce behaviour common to descendants.

Look at the last example, just above. What exactly is a "Shape"? It could be described, maybe, as an enclosed space. However, maybe this description doesn't fit with your idea of a shape. You can't really be certain of what a shape is. If I asked you to "draw a shape" you might draw a circle, a square, or whatever. If I then said to you, "No! You're drawing a descendant of a shape. I said draw a shape!" you would get a little confused. It looks like we shouldn't really have a Shape, because it doesn't seem very easily defined.

The base class here, though, is handy. It can clearly define behaviour for the object (such as "Draw"). It should exist, then, but only as a starting point to introduce common functionality into its derived classes. Therefore, it seems, we should have it but shouldn't let it be created. Hence, it should be abstract.

To create an abstract class you just need to declare at least one virtual method as "abstract". It must be a virtual method, of course, because as you can't create an abstract class any attempt to access the method must be routed correctly to one of the base classes. Here's an example of changing the base class (TMyShape) to be abstract:

type
  TMyShape = class
  public
    procedure Draw(x,y: Integer); virtual; abstract;
  end;

That's all there is to it! And with this, I must leave now (I'm the guy who mugs people and throws their wallets through the ATM money gap ;-)).

   Question, Suggestions...
If you have any questions or comments to this (huge) article, please post them on the Delphi Programming Forum. Discuss!

First page > About components > Page 1, 2, 3, 4, 5, 6, 7, 8, 9

All graphics (if any) in this feature created by Zarko Gajic.

 More Delphi
· Learn another routine every day - RTL Quick Reference.
· Download free source code applications and components.
· Talk about Delphi Programming, real time.
· Link to the Delphi Programming site from your Web pages.
· Tutorials, articles, tech. tips by date: 2001|2000|1999|1998 or by TOPIC.
· NEXT ARTICLE: GDI Graphics In Delphi.
From simple lines to direct API calls: the ultimate tutorial to GDI graphics in Delphi. This tutorial will introduce you to some of the techniques in the GDI Delphi drawing. Look for: drawing lines and shapes, drawing pictures, flicker-free drawings, off-screen bitmaps, GDI drawings the API way...
 Stay informed with all new and interesting things about Delphi (for free).
Subscribe to the Newsletter
Name
Email

 Got some code to share? Got a question? Need some help?

©2014 About.com. All rights reserved.