RAD Studio |  |

Object-oriented programming for component writers
Collapse All
Topics

Name | Description
Object-oriented Programming for Component Writers: Overview | If you have written applications with Delphi, you know that a class contains both data and code, and that you can manipulate classes at design time and at runtime. In that sense, you've become a component user. When you create new components, you deal with classes in ways that application developers never need to. You also try to hide the inner workings of the component from the developers who will use it. By choosing appropriate ancestors for your components, designing interfaces that expose only the properties and methods that developers need, and following the other guidelines in the following topics,... more
Defining New Classes | The difference between component writers and application developers is that component writers create new classes while application developers manipulate instances of classes. A class is essentially a type. As a programmer, you are always working with types and instances, even if you do not use that terminology. For example, you create variables of a type, such as Integer. Classes are usually more complex than simple data types, but they work the same way: By assigning different values to instances of the same type, you can perform different tasks. For example, it is quite common to create a form... more
Deriving New Classes | There are two reasons to derive a new class: To change class defaults to avoid repetition To add new capabilities to a class In either case, the goal is to create reusable objects. If you design components with reuse in mind, you can save work later on. Give your classes usable default values, but allow them to be customized.
Abstract Class Members | When a method is declared as abstract in an ancestor class, you should surface it (by redeclaring and implementing it) in any descendant component before you use the new component in applications. On the Win32 platform, Delphi can create instances of a class that contains abstract members. This is not recommended, however. For more information about surfacing inherited parts of classes, see Creating properties and Creating methods.
Adding New Capabilities to a Class | A common reason for creating new components is to add capabilities not found in existing components. When you do this, you derive the new component from either an existing component or an abstract base class, such as TComponent or TControl. Derive your new component from the class that contains the closest subset of the features you want. You can add capabilities to a class, but you cannot take them away; so if an existing component class contains properties that you do not want to include in yours, you should derive from that component's ancestor. For example, if you want... more
Ancestors, Descendants, and Class Hierarchies | Application developers take for granted that every control has properties named Top and Left that determine its position on the form. To them, it may not matter that all controls inherit these properties from a common ancestor, TControl. When you create a component, however, you must know which class to derive it from so that it inherits the appropriate features. And you must know everything that your control inherits, so you can take advantage of inherited features without recreating them. The class from which you derive a component is called its immediate ancestor. Each component inherits from its... more
Changing Class Defaults to Avoid Repetition | Most programmers try to avoid repetition. Thus, if you find yourself rewriting the same lines of code over and over, you place the code in a subroutine or function, or build a library of routines that you can use in many programs. The same reasoning holds for components. If you find yourself changing the same properties or making the same method calls, you can create a new component that does these things by default. For example, suppose that each time you create an application, you add a dialog box to perform a particular operation. Although it is not difficult to... more
Controlling Access | There are five levels of access control - also called visibility - on properties, methods, and fields. Visibility determines which code can access which parts of the class. By specifying visibility, you define the interface to your components. The table below shows the levels of visibility, from most restrictive to most accessible: Levels of visibility within an object
Declaring a New Component Class | In addition to standard components, Delphi provides many abstract classes designed as bases for deriving new components. The Creating components topic shows the classes you can start from when you create your own components. To declare a new component class, add a class declaration to the component's unit file.
Defining the Design-time Interface | Declaring part of a class as published makes that part public and also generates runtime type information. Among other things, runtime type information allows the Object Inspector to access properties and events. Because they show up in the Object Inspector, the published parts of a class define that class's design-time interface. The design-time interface should include any aspects of the class that an application developer might want to customize at design time, but must exclude any properties that depend on specific information about the runtime environment. Read-only properties cannot be part of the design-time interface because the application developer... more
Defining the Component Writer's Interface | Declaring part of a class as protected makes that part visible only to the class itself and its descendants (and to other classes that share their unit files). You can use protected declarations to define a component writer's interface to the class. Application units do not have access to the protected parts, but derived classes do. This means that component writers can change the way a class works without making the details visible to application developers. Note: A common mistake is trying to access protected methods from an event handler. Event handlers are typically methods of the form, not the... more
Defining the Runtime Interface | Declaring part of a class as public makes that part visible to any code that has access to the class as a whole. Public parts are available at runtime to all code, so the public parts of a class define its runtime interface. The runtime interface is useful for items that are not meaningful or appropriate at design time, such as properties that depend on runtime input or which are read-only. Methods that you intend for application developers to call must also be public.
Dispatching Methods | Dispatch refers to the way a program determines where a method should be invoked when it encounters a method call. The code that calls a method looks like any other procedure or function call. But classes have different ways of dispatching methods. The three types of method dispatch are Static Virtual Dynamic
Dynamic Methods | Dynamic methods are virtual methods with a slightly different dispatch mechanism. Because dynamic methods don't have entries in the object's virtual method table, they can reduce the amount of memory that objects consume. However, dispatching dynamic methods is somewhat slower than dispatching regular virtual methods. If a method is called frequently, or if its execution is time-critical, you should probably declare it as virtual rather than dynamic. Objects must store the addresses of their dynamic methods. But instead of receiving entries in the virtual method table, dynamic methods are listed separately. The dynamic method list contains entries only for methods... more
Hiding Implementation Details | Declaring part of a class as private makes that part invisible to code outside the class's unit file. Within the unit that contains the declaration, code can access the part as if it were public.
Virtual Methods | Virtual methods employ a more complicated, and more flexible, dispatch mechanism than static methods. A virtual method can be redefined in descendant classes, but still be called in the ancestor class. The address of a virtual method isn't determined at compile time; instead, the object where the method is defined looks up the address at runtime. To make a method virtual, add the directive virtual after the method declaration. The virtual directive creates an entry in the object's virtual method table, or VMT, which holds the addresses of all the virtual methods in an object type. When you derive... more
Classes and Pointers | Every class (and therefore every component) is really a pointer. The compiler automatically dereferences class pointers for you, so most of the time you do not need to think about this. The status of classes as pointers becomes important when you pass a class as a parameter. In general, you should pass classes by value rather than by reference. The reason is that classes are already pointers, which are references; passing a class by reference amounts to passing a reference to a reference.
Overriding Methods | Overriding a method means extending or refining it, rather than replacing it. A descendant class can override any of its inherited virtual methods. To override a method in a descendant class, add the directive override to the end of the method declaration. Overriding a method causes a compilation error if The method does not exist in the ancestor class. The ancestor's method of that name is static. The declarations are not otherwise identical (number and type of arguments parameters differ).
Regular Methods (C++) | Class methods are regular (or nonvirtual) unless you specifically declare them as virtual, or unless they override a virtual method in a base class. The compiler can determine the exact address of a regular class member at compile time. This is known as compile-time binding. A base class regular method is inherited by derived classes. In the following example, an object of type Derived can call the method Regular() as it were its own method. Declaring a method in a derived class with the same name and parameters as a regular method in the class's ancestor replaces the ancestor's... more
Static Methods | All methods are static unless you specify otherwise when you declare them. Static methods work like regular procedures or functions. The compiler determines the exact address of the method and links the method at compile time. The primary advantage of static methods is that dispatching them is very quick. Because the compiler can determine the exact address of the method, it links the method directly. Virtual and dynamic methods, by contrast, use indirect means to look up the address of their methods at runtime, which takes somewhat longer. A static method does not change when inherited by a descendant class.... more

Copyright(C) 2009 Embarcadero Technologies, Inc. All Rights Reserved.
What do you think about this topic? Send feedback!