1. Home
  2. Computing & Technology
  3. Delphi Programming
RTL referenceGlossary|Tips/Tricks|FREE App/VCL|Best'O'Net|Books|Link To
 
Creating Custom Delphi Components - Inside and Out
Page 8: Explaining - "public", "private", "protected" and "published"
 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 9: Virtual functions and Abstract Classes
 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

   Hiding data
Now it's time for something I really should have discussed two tutorial parts ago (whoops!). I've been using "public", "private", "protected" and "published" at various parts throughout this tutorial, but I haven't explained them. You are now ready, grasshopper.

One reason why object-oriented design is funky is because it allows you to hide the hard work behind-the-scenes of an object. For example, if you're using an ATM machine (which seems to be a standard thing to use for O.O. examples, don't ask me why) you put in your card, enter your pin, hope you have enough money and enter in how much you want. You then (hopefully) get some money back. You don't care how the money gets to you - it could be stored in some automatic dispensing machine, slaves could push it through the gap, people could be mugged and their wallet contents thrown through the gap. It doesn't matter - you say "give me cash" and the ATM gives you cash. How it does this is entirely up to it.

What if your ATM didn't have a screen, but just a big hole with a bucket of cash? It could trust you to be honest and take the right amount, but sooner or later you'd take too much (and you'd then get shot, because banks ain't that dumb and it was a trap :-p). Because you had access to the direct internals of the ATM machine everything ran on pure trust. If somebody messes around, either maliciously or by accident, then your system is screwed! So how do we replicate this hiding of data using classes? We do this using the aforementioned keywords (private, protected, public and published).

Incidentally, to introduce another jargon word, the process of hiding data away and making the world use some predefined interface to get at it is known as encapsulation. It allows the system to change its internal structure without causing disruption, as long as the same interface is used (which might mean get/set functions or properties).

Private
The first of the keywords, "private", does this job perfectly. If you declare something as private then only that class can access the data or method. Any attempt to access it in the outside world causes an error, because it's not visible to them. For example:

type
  TSafeClass = class(TObject)
  private
    FSomeData: Integer;
  public
    constructor Create(const startValue: Integer);
  end;

implementation

constructor TSafeClass.Create(const startValue: Integer);
begin
  inherited Create;
  FSomeData := StartValue;
end;

//-----------------------------------------
// In the outside world (i.e. another unit)
procedure TForm1.DoSomething;
begin
  if FMySafeClass.FSomeData = 21 then // nope: "Unknown Identifier" error
    ShowMessage('This doesn''t work!');
end;

This class safely hides data away from the outside world. Any attempt to access "SomeObject.FSomeData" will result in an error ("unknown identifier") because it just isn't available to the outside world. It's like you trying to reprogram the CPU of the ATM machine... how can you do it? You can't even see it! (That's not an invitation to try, by the way ;-). )

There are a couple of exceptions to this, however (as always). If you declare multiple classes in the same unit (for example another class in a form's unit) then the private keyword doesn't seem to apply, and you can see private data of that class from within the form. This behaviour came as a complete surprise to me, but c'est la vie. You should declare classes in separate units - in any case, it's cleaner.

The other exception is this: different object instances of the same type can access each other's private data. So, for example:

type
  TBlah = class(TObject)
  private
    FSomedata: Integer;
  public
    constructor Create(startValue: Integer);
    function Compare(const Something: TBlah): Boolean;
  end;

implementation

constructor TBlah.Create(startValue: Integer);
begin
  inherited Create;
  FSomeData := startValue;
end;

function TBlah.Compare(const Something: TBlah): Boolean;
begin
  Result := (FSomeData = Something.FSomeData);
end;

This class's Compare function works perfectly fine, despite accessing private data. It's only the outside world that can't access the data, not other instances of the same class. Call this a quirk of classes (it's the same in C++ too, for example).

Of course, you can hide anything using the Private keyword, not just variables. You can also hide events, methods and properties if you want.

Protected
The second important keyword, Protected, behaves in a similar way to Private, but with one important difference - derived classes can see the data too. This is different from Private, which doesn't allow this. So, for example:

type
  THideMe = class(TObject)
  protected
    FSomeData: Integer;
  public
    constructor Create(StartValue: Integer);
  end;

implementation

constructor THideMe.Create(StartValue: Integer);
begin
  inherited Create;
  FSomeData := StartValue;
end;

If you later declare a class such as this (in a different unit, to keep things tidy):

type
  TDerived = class(THideMe);

then the TDerived class gets access to the FSomeData variable. It can use it as if you'd declared the variable in TDerived, instead of THideMe. If you tried the same thing with the Private keyword you wouldn't be able to do this.

Protected still hides stuff away from the outside world. You can't access the data in some other form, of course, because you'd wind up with another "unknown identifier" compiler error. Protected offers a different, and slightly more flexible, way to hide data from the outside world.

Public
The third keyword is Public. This is used to declare things that will be completely visible to the outside world. It is used to declare an interface for your class. If you write public get/set functions (or better still, properties) then you can control how the outside world deals with your class. The outside world must use these public methods to access the data, so there's no "bucket of cash" syndrome.

Now for an aside: usually, constructors and destructors will be declared as public, since it's most common for the outside world to want to create objects. You may have taken the "public" keyword in front of constructors and destructors for granted. However, you can have private or protected constructors as well.

Anyway, here's an example of how using Public can make your component data nicely encapsulated:

type
  TSomething = class(TObject)
  private
    FPrivateData: Integer;
    procedure SetPrivateData(NewValue: Integer);
  public
    constructor Create(StartValue: Integer);
    property Data: Integer read FPrivateData write SetPrivateData;
  end;

constructor TSomething.Create(StartValue: Integer);
begin
  inherited Create;
  FPrivateData := StartValue;
end;

procedure TSomething.SetPrivateData(NewValue: Integer);
begin
  if (NewValue <> FPrivateData) and (NewValue >= 0) then
    FPrivateData := NewValue;
end;

This example looks pretty innocuous. However, it demonstrates the principle of encapsulating your data. The outside world uses the property "Data" to access the data. When they try to change Data, the change is checked first. The code in SetPrivateData, of course, is just an example. It's easy to picture how an ATM class could change this kind of code to say:

if (FBucketOfCash) and 
          (AmountTaken > AccountHolder.FBalance) then
  ShootThief;

... for example :-). Hopefully now you see the value of encapsulating your data. There's still one keyword left, so let's discuss that now...

Published
Published is just an extension of Public. As Delphi has a visual IDE it needs a way to say what will get displayed in the Object Inspector. If you want to make any properties/events available to the user at design-time, declare them as published. There ain't much more to say about published, except that you can see it in action by reviewing the TLine component.

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

Next page > Virtual functions and Abstract Classes > 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?
Explore Delphi Programming
About.com Special Features

Holiday Central

What to eat, where to go, fun things to do and how to save money on the perfect gifts. More >

Family Tech Center

Stay connected and entertained with reviews on tips on the latest HDTVs, cellphones and more. More >

  1. Home
  2. Computing & Technology
  3. Delphi Programming

©2009 About.com, a part of The New York Times Company.

All rights reserved.