Last Updated:

Scope | Delphi | Tutorial

When describing a new class, a reasonable compromise is important. On the one hand, it is necessary to hide from others the methods and fields that represent the internal structure of the class (for this purpose the properties were invented). Unimportant details at the user level of the object will be useless and will only interfere with the integrity of perception.

On the other hand, if you limit too much who will generate descendant classes, and do not provide him with a sufficient set of tools and freedom of maneuver, then he will not use your class.

In the Object Pascal object model, there is a mechanism for accessing the constituent parts of an object that defines the areas where they can be used (scopes). Fields and methods can belong to four groups (sections) that differ in scopes. Methods and properties can be shared (public section), private (private section), protected (protected section), and published (published section). There is also a fifth group, automated, which was previously used to create COM objects; now it is present in the language only for backward compatibility with programs on Delphi versions 3-5.

The scopes defined by the first three directives are as follows.

  • The fields, properties, and methods of the public section have no visibility restrictions. They are available from other functions and methods of objects both in this module and in all others that refer to it.
  • The fields, properties, and methods in the private section are available only in class methods and functions contained in the same module as the class being described. Such a directive allows you to completely hide the details of the internal implementation of the class. You can change the properties and methods in the private section, and this will not affect programs that work with objects of this class. The only way for someone else to contact them is to rewrite the module you created again (unless, of course, the source code is available).
  • The fields, properties, and methods of the protected section are also available only within the module with the class being described. But – and this is the main thing – they are available in classes that are descendants of this class, including other modules. Such elements are especially necessary for developers of new components – descendants of existing ones. While leaving the freedom to modernize a class, they still hide the details of the implementation from someone who only uses objects of this class.

Consider an example that illustrates three variations of scopes.

Code Listing 1.1. An example of setting the scopes of methods.

unit First; | unit Second;
interface | interface
| uses First;
type | type
TFirstObj = class | TSecondObj =class(TFirstObj}
private | procedure Method4;
procedure Method1; | end;
protected |
procedure Method2; |
public |
procedure Methods; |
end; |
procedure TestProcl; | procedure TestProc2;
implementation | implementation
uses dialogs; | varAFirstObj:TFirstObj;
var AFirstObj: TFirstObj;|ASecondObj: TSecondObj;
procedure TestProcl; | procedure TSecondObj.Method4;
begin | begin
AFirstCbj := TFirstObj.Create; | method1; {invalid - a compilation error will occur}
AFirstObj.Method1;(valid)|
AFirstObj.Method2; {valid}| method2; {permissible}
AFirstObj.MethodS; {valid}| Method3, - {valid}
AFirstObj.Free; | end;
end;
| procedure TestProc2;
procedure TFirstObj.Method1; | begin
begin |AFirstObj := TFirstObj.Create;
ShowMessage('1'); |AFirstObj.Method1;{invalid}
end; |AFirstObj.Method2;{invalid}
procedure TFirstObj.Method2;
|AFirstObj.Method3;{valid}
begin |AFirstObj.Free;
ShowMessage('2');
methodl; |ASecondCbj := TSecondObj.Create;
end; |ASecondObj.Method1;{invalid}
procedureTFirstObj.Method3;
|ASecondObj.Method2;{valid}
begin |ASecondObj.Method3;{valid}
ShowMessage('3'); |ASecondObj.Free;
method2; | end;
end; |end.
end. |

If you add the Third module to this example and try to call the methods of the TFirstObj and TSecondObj classes from there, then Method2 will be included among the unavailable ones - it is available only in the module in which it is described.

Finally, the scope defined by the fourth directive, published, is of particular importance for the Delphi visual design interface. In this section, you should collect those properties of the object that will be visible not only during the execution of the application, but also from the development environment. You can publish properties of most types, with the exception of the old real type (now called real), array properties, and some others. All component properties available through the Object inspector are their published properties. At run time, such properties are publicly available, as is public.

The three scopes — privateprotectedpublic — are sort of ordered by increasing visibility of the methods. In child classes, you can increase the visibility of methods and properties, but not downgrade it. When describing a child class, you can transfer methods and properties from one sphere of view to another without rewriting them again or even describing them — just mention it elsewhere:

type
TFirstObj = class
private
FNumber: Integer;
protected
property Number: Integer read: FNumber;
end;
…
TSecondObj = class(TFirstObj)
published
property Number;
end;

If any property of a VCL object belongs to the public scope, it cannot be returned to private. In contrast, the reverse procedure is widely practiced in Delphi. Many components (e.g., TEdit) have an ancestor (in this case, TCustomEdit) that differs only in the absence of published properties.

So if you want to create a new editing component, spawn it from TCustomEdit and publish only the properties you see fit. Of course, if you put the property in the private area, it is no longer possible to "get" it from there in the descendants.