First, you should get familiar with "components", which are a little bit different from class. Well I do not know exactly, but components look like "drop" boxes, like TMemo, TButton, etc., which you can drop from component palletts, and whose "published' properties you can edit at the object inspector (and you can access them within codes as well). There are other properties (and functions and procedures as well) which are "public", which you can access within codes (but not from object inspector). You can see available public properties and methods from the help box, which pops up after you type like Edit1. and wait for a while.
A small explanation (correction) is needed here. Components are not some unusual (or atypical) classes. They are very much ordinary classes. Classes are organized in a hierarchical inheritance tree. One such class in this tree is
TComponent. Others are
TPersistent,
TControl,
TGraphicControl or
TWinControl. Depending on which of these classes our classes (that we create) or library classes come from, they are treated differently in the IDE. In particular, in that part of it called:
Object inspector.
In Object Pascal, all classes have one common ancestor:
TObject. There is no such thing in C++, because it uses a multiple inheritance model. It has some advantages, but also a lot of disadvantages. On the other hand, in languages such as C# and Java, there is also one common ancestor of all classes (this allows to avoid various conflicts in the implementation of classes).
In Object Pascal, classes have 4 levels of visibility: private, protected, public and published. The first three scopes work more or less like in C++. The last scope (i.e. published) exists so that certain features of classes are available from the
Object Inspector. Classes in Object Pascal can have the following elements (in short):
- private scope: fields, methods (including so-called access methods: GetXyz, SetXyz), event fields,
- protected scope: fields, methods (including so-called access methods: GetXyz, SetXyz), events,
- public scope: properties (read-only, read/write), methods, events,
- published: properties only (read/write), events.
Properties are a mechanism for accessing class fields. Thanks to it, you can create read-only fields (and theoretically also write-only, but this is rather useless). The second purpose is to control data entered into the class (e.g. data verification). Properties can be of the following types:
- simple: boolean values, characters, enumerated values, integer numbers, real numbers,
- complex: sets, strings, arrays, records (structures), classes.
Access methods are used to support properties: reading (GetXyz) or writing (SetXYz). But they don't have to be implemented explicitly. You can also create properties that read and set fields directly. There can also be properties in a class that don't have a corresponding field, when, for example, the return value is calculated. A specific type of property is an event. An event is essentially a type of callback. Such a field in a class stores a pointer to a method present in another class. If the pointer is not
nil (equivalent to
nullptr in C++), then the method can be called.
The
Object inspector allows you to manually modify the value of properties in specific classes. The condition for this is that the class being created must derive from at least
TComponent. If we want a property of such a class to be available for editing, it should be declared in the published section. Similarly, if we want to associate an event of a given class with a method in the
Object inspector (or create such a method in the code editor), the event must be declared in the published section (the event, not the field handling it!). Properties and events are displayed in separate tabs of the
Object inspector because they work differently. However, class methods are not visible in the
Object inspector.
If we want a complex property (e.g. containing many of its own internal properties) to be visible in the
Object inspector, then such a property must be a class, additionally derived from
TPersistent.
Classes used to build GUIs are derived from
TControl (in some libraries called: widget). There are two types: graphic (
TGraphicControl) and window (
TWinControl). Window controls have: a system handle, canvas, message queue and can get focus (like e.g.
TForm,
TButton,
TEdit,
TPanel,
TScrollBox). Therefore, they burden the system a bit. Graphic controls do not have their own canvas (they are drawn on the parent canvas) and cannot get focus (like e.g.
TImage,
TLabel,
TPaintBox).
ObjectPascal classes can have virtual methods, which can be redefined in descendant classes. Access methods can also be virtual. Furthermore, methods can be overloaded (i.e., same names, but different number and types of arguments). There are no friend functions, but you can achieve something close.
ObjectPascal classes can have any number of constructors. Constructors can be virtual and can also be overloaded. There are no copy constructors. Classes can have methods: Assign and AssignTo, which are used to make deep copies of objects.
ObjectPascal classes can have only one destructor. Destructors can be virtual.
A class can have fields that are themselves classes. Then such a class is the owner of these nested classes. The owning class must create internal objects that are stored in the fields. These internal objects may be created in the class's constructor or methods. In the destructor of the owning class, all internal (nested) objects must be removed (destroyed).
Control classes used to build GUIs can be used in a graphical form editor. Objects of these classes are taken from the palette and placed on an empty window. In addition, some of the controls themselves can contain other controls placed on top of each other (layered one on top of the other). The main control (platform) is the window form (
TForm). The class that is the area on which other controls are placed is called the parent. The parent-child relationship applies to the GUI and should not be confused with the owner-ownership relationship.
Each unit in Pascal and Object Pascal has a public section (keyword: interface) and a private section (keyword: implementation). In both of them, you can specify used library modules (keyword: uses). You don't have to add this word (i.e. uses) to each module, as you have to do in C and C++ with the word #include - why such terrible verbosity?).
Units can have initialization and finalization sections. They are placed at the end of the module. They are used to place instructions there that will be executed once the module is loaded (initialization) or unloaded (finalization). This of course applies to modules in compiled form. In Pascal and Object Pascal, you don't need to add something like header guards, precisely because of the modularization of the code.
It is worth mentioning the existence of generalized types and the possibility of specifying constraints in these types. This is a way of writing code that is to some extent independent of types (the equivalent of templates in C++). A specific type is specified only in code that uses such a general type. It is also possible to overload operators (to a limited extent).
And finally, the so-called type helpers. They are particularly useful for handling simple types, but they can also be used for classes. Helpers allow treating variables or constants of simple types as if they were objects. This is a kind of syntactic sugar, but it greatly simplifies the code and improves its readability.