# Metaclasses
A metaclass (or class reference) is a type that refers to a class itself, rather than an instance of a class. This allows for powerful dynamic instantiation patterns and reflective programming.
## Syntax
Metaclasses are declared using the `class of` syntax.
```pascal
type
TBase = class
constructor Create; virtual; begin end;
end;
type
TDerived = class(TBase)
constructor Create; override; begin end;
end;
type
TBaseClass = class of TBase;
// OUTPUT NONE
```
## Dynamic Instantiation
The primary use of metaclasses is to create objects when the exact class is only known at runtime.
```pascal
type
TBase = class
constructor Create; virtual; begin end;
end;
type
TDerived = class(TBase)
constructor Create; override; begin end;
end;
type
TBaseClass = class of TBase;
var cls: TBaseClass := TDerived;
var obj := cls.Create;
PrintLn(obj.ClassName);
// OUTPUT
// TDerived
```
### Virtual Constructors
For polymorphic instantiation to work correctly, the constructor must be declared as `virtual` in the base class and `override` in the subclasses. If you call a non-virtual constructor on a metaclass, the base class constructor will be called regardless of the class the metaclass variable currently holds.
## Class Methods and Properties
Metaclasses can be used to call class methods and access static properties.
```pascal
type
TUtility = class
class procedure DoSomething;
begin
PrintLn('Doing something...');
end;
end;
type
TUtilityClass = class of TUtility;
var v: TUtilityClass := TUtility;
v.DoSomething;
// OUTPUT
// Doing something...
```
## Type Checking and Casting
The `is` and `as` operators are used to check and cast object instances.
```pascal
type
TBase = class
constructor Create; virtual; begin end;
end;
type
TDerived = class(TBase)
constructor Create; override; begin end;
end;
type
TBaseClass = class of TBase;
var obj: TObject := TDerived.Create;
if obj is TBase then
PrintLn('obj is a TBase');
var cls: TBaseClass := TDerived;
if obj is cls then
PrintLn('obj is an instance of ' + cls.ClassName);
var d := obj as TDerived;
PrintLn(d.ClassName);
// OUTPUT
// obj is a TBase
// obj is an instance of TDerived
// TDerived
```
## TClass and ClassType
Every object has a `ClassType` property that returns its metaclass. `TClass` is the base metaclass for all classes.
```pascal
type
TDerived = class
end;
var obj: TObject := TDerived.Create;
var anyClass: TClass := obj.ClassType;
PrintLn(anyClass.ClassName);
// OUTPUT
// TDerived
```
Metaclasses
A metaclass (or class reference) is a type that refers to a class itself, rather than an instance of a class. This allows for powerful dynamic instantiation patterns and reflective programming.
Syntax
Metaclasses are declared using the class of syntax.
type
TBase =classconstructor Create;virtual;beginend;end;type
TDerived =class(TBase)constructor Create;override;beginend;end;type
TBaseClass =classof TBase;
Dynamic Instantiation
The primary use of metaclasses is to create objects when the exact class is only known at runtime.
For polymorphic instantiation to work correctly, the constructor must be declared as virtual in the base class and override in the subclasses. If you call a non-virtual constructor on a metaclass, the base class constructor will be called regardless of the class the metaclass variable currently holds.
Class Methods and Properties
Metaclasses can be used to call class methods and access static properties.
The is and as operators are used to check and cast object instances.
type
TBase =classconstructor Create;virtual;beginend;end;type
TDerived =class(TBase)constructor Create;override;beginend;end;type
TBaseClass =classof TBase;var obj:TObject:= TDerived.Create;if obj is TBase then
PrintLn('obj is a TBase');var cls: TBaseClass := TDerived;if obj is cls then
PrintLn('obj is an instance of '+ cls.ClassName);var d := obj as TDerived;
PrintLn(d.ClassName);
Result
obj is a TBase
obj is an instance of TDerived
TDerived
TClass and ClassType
Every object has a ClassType property that returns its metaclass. TClass is the base metaclass for all classes.
type
TDerived =classend;var obj:TObject:= TDerived.Create;var anyClass: TClass := obj.ClassType;
PrintLn(anyClass.ClassName);