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.
Metaclasses are declared using the class of syntax.
type
TBase = class
constructor Create; virtual; begin end;
end;
type
TDerived = class(TBase)
constructor Create; override; begin end;
end;
type
TBaseClass = class of TBase; The primary use of metaclasses is to create objects when the exact class is only known at runtime.
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); TDerived
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.
Metaclasses can be used to call class methods and access static properties.
type
TUtility = class
class procedure DoSomething;
begin
PrintLn('Doing something...');
end;
end;
type
TUtilityClass = class of TUtility;
var v: TUtilityClass := TUtility;
v.DoSomething; Doing something...
The is and as operators are used to check and cast object instances.
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); obj is a TBase obj is an instance of TDerived TDerived
Every object has a ClassType property that returns its metaclass. TClass is the base metaclass for all classes.
type
TDerived = class
end;
var obj: TObject := TDerived.Create;
var anyClass: TClass := obj.ClassType;
PrintLn(anyClass.ClassName); TDerived