The last language feature I'll discuss in this chapter is the use of class references, which implies the idea of manipulating classes themselves within your code. The first point to keep in mind is that a class reference isn't an object; it is a reference to a class type. A class reference type determines the type of a class reference variable.
Sounds confusing? A few lines of code will make this concept a little clearer.
Suppose you have defined the class TMyClass. You can now define a new class reference type, related to that class:
type
TMyClassRef = classof TMyClass;
Now you can declare variables of both types. The first variable refers to an object, the second to a class:
var
You may wonder what class references are used for. In general, class references allow you to manipulate a class data type at run time. You can use a class reference in any expression where the use of a data type is legal. There are not many such expressions, but the few cases are interesting, like the creation of an object. You can rewrite the last line of the previous code as follows:
AnObject := AClassRef.Create;
This time, you apply the Create constructor to the class reference instead of to an actual class; you use a class reference to create an object of that class.
Class reference types wouldn't be as useful if they didn't support the same type-compatibility rule that applies to class types. When you declare a class reference variable, such as MyClassRef, you can then assign to it that specific class and any inherited class. So if TMyNewClass is an inherited class of TMyClass my class, you can also write
AClassRef := TMyNewClass;
Delphi declares a lot of class references in the run-time library and the VCL, such as the following:
TClass = class of TObject;
TComponentClass = class of TComponent;
TFormClass = class of TForm;
In particular, the TClass class reference type can be used to store a reference to any class you write in Delphi, because every class is ultimately derived from TObject. The TFormClass reference is used in the source code of most Delphi projects. The CreateForm method of the Application object requires as a parameter the class of the form to create:
Application.CreateForm(TForm1, Form1);
The first parameter is a class reference; the second is a variable that stores a reference to the created object instance.
Finally, when you have a class reference, you can apply to it the class methods of the related class. Considering that each class inherits from TObject, you can apply to each class reference some of the methods of TObject, as you'll see in Chapter 3.
Creating Components Using Class References
What is the practical use of class references in Delphi? Being able to manipulate a data type at run time is a fundamental element of the Delphi environment. When you add a new component to a form by selecting it from the Component Palette, you select a data type and create an object of that data type. (Actually, that is what Delphi does for you behind the scenes.) In other words, class references give you polymorphism for object construction.
This document was created by an unregistered ChmMagic, please go to http://www.bisenter.com to register it. Thanks .
To give you a better idea of how class references work, I've built an example named ClassRef. The form displayed by this example has three radio buttons, placed inside a panel in the upper portion
of the form. When you select one of these radio buttons and click the form, you'll be able to create new components of the three types indicated by the button labels: radio buttons, push buttons, and edit boxes.
To make this program run properly, you need to change the names of the three components. The form must also have a class reference field, declared as ClassRef:TControlClass. It stores a new data type every time the user clicks one of the three radio buttons, with assignments like ClassRef:= TEdit. The interesting part of the code is executed when the user clicks the form. Again, I've chosen the OnMouseDown event of the form to hold the position of the mouse click:
procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var
NewCtrl: TControl;
MyName: String;
begin
// create the control
NewCtrl := ClassRef.Create (Self);
// hide it temporarily, to avoid flickering NewCtrl.Visible := False;
// set parent and position NewCtrl.Parent := Self;
NewCtrl.Left := X;
NewCtrl.Top := Y;
// compute the unique name (and caption) Inc (Counter);
MyName := ClassRef.ClassName + IntToStr (Counter);
Delete (MyName, 1, 1);
NewCtrl.Name := MyName;
// now show it
NewCtrl.Visible := True;
end;
The first line of the code for this method is the key. It creates a new object of the class data type stored in the ClassRef field. You accomplish this by applying the Create constructor to the class reference. Now you can set the value of the Parent property, set the position of the new component, give the component a name (which is automatically used also as the value of Caption or Text), and make it visible. You can see an example of the output of this program in Figure 2.9.
Figure 2.9: An example of the output of the ClassRef example
Note For polymorphic construction to work, the base class type of the class reference must have a virtual constructor. If you use a virtual constructor (as in the example), the constructor call applied to the class reference will call the constructor of the type that the class reference variable currently refers to. But without a virtual constructor, your code will call the constructor of fixed class type indicated in the class reference declaration. Virtual constructors are required for polymorphic construction in the same way that virtual methods are required for polymorphism.
This document was created by an unregistered ChmMagic, please go to http://www.bisenter.com to register it. Thanks.
What's Next?
In this chapter, we have discussed the foundations of object-oriented programming (OOP) in Delphi. We have considered the definition of classes and the use of methods, encapsulation, and memory management, but also some more advanced concepts such as properties and the dynamic creation of components. Then we moved to inheritance, virtual and abstract methods, polymorphism, safe typecasting, interfaces, exceptions, and class references.
This is certainly a lot of information if you are a newcomer. But if you are fluent in another OOP language or if you've already used past versions of Delphi, you should be able to apply the topics covered in this chapter to your
programming.
Understanding the secrets of Delphi's language and library is vital for becoming an expert Delphi programmer. These topics form the foundation of working with the VCL and CLX class libraries; after exploring them in the next two chapters, we'll finally go on to explore the development of real applications using all the various components provided by Delphi.
In the meantime, Chapter 3 will give you an overview of the Delphi run-time library (mainly a collection of functions with little OOP involved). The RTL is a collection of assorted routines for performing basic tasks with Delphi. Chapter 4 will give you more information about the language, discussing features related to the structure of the Delphi class library, such as the effect of the published keyword and the role of events. That chapter, as a whole, will discuss the overall architecture of the component library.
Chapter 3: The Run-Time Library
Overview
The Delphi programming language favors an object-oriented approach, tied with a visual development style. This is where Delphi shines, and we will cover component-based and visual development in this book; however, I want to underline the fact that many of Delphi's ready-to-use features come from its run-time library (RTL). This is a large collection of functions you can use to perform simple tasks, as well as some complex ones, within your Pascal code. (I use "Pascal" here, because the run-time library primarily contains procedures and functions written with the traditional language constructs and not the OOP extensions added to the language by Borland.)
There is a second reason to devote this chapter of the book to the run-time library: Delphi 6 saw a large number of enhancements to this area, and a few more are provided in Delphi 7. New groups of functions are available, functions have been moved to new units, and other elements have changed, creating a few incompatibilities with older code from which you might be porting your projects. So, even if you've used past versions of Delphi and feel confident with the RTL, you should still read at least portions of this chapter.
This document was created by an unregistered ChmMagic, please go to http://www.bisenter.com to register it. Thanks.