Take Away: Implement static member data in Delphi with variables declared in the implementation section (unit scope). Increment and decrement variable in constructor and destructor. Then use a class function to surface the variable's value publicly.
KB101713
Introduction
For our instance counter, if no classes are currently created, the current value of your instance counter needs to be 0. For each class created, you add 1. For each destroyed, you subtract 1. This article will utilize static data and a class method to build an instance counter. This is not a generic instance counter but rather a simple build-it-per-class instance counter.
This article will utilize an initialized unit variable (a variable initialized to 0 in the implementation section of a unit) and a class method to build an instance counter for a specific class.
Static Data:Static data (a.k.a. static class member) is data of a class that retains state (it's value) whether or not there is an instance of a class. In Delphi, you implement static data using either global variables (declared in the interface section) or unit variables (declared in the implementation section).
Class Methods: A Delphi class method (a.k.a. static method) is a method you can call without instantiating the class. It's called a class method since it belongs to the class and not to a specific object created from the class. A static class is a class that contains only static members (class members).
Build-It!
The following is a class that demonstrates initializing a global variable for use as an instance counter:
unit ObjectCounter;
interface
type TObjectCounter = class(TObject) public constructor Create; virtual; destructor Destroy; override; class function GetInstanceCount: Integer; end;
implementation
{ TObjectCounter }
//Declared here rather than in interface section to limit the
//scope to this unit. Otherwise, we would probably run into
//variable naming conflicts.
var TObjectCounterCount: Integer=0;
constructor TObjectCounter.Create; begin inherited; TObjectCounterCount := TObjectCounterCount + 1; end;
destructor TObjectCounter.Destroy; begin TObjectCounterCount := TObjectCounterCount - 1; inherited; end;
//Class function so you don't have to create
//the class to call this function.
class function TObjectCounter.GetInstanceCount: Integer; begin Result := TObjectCounterCount; end;
end.
Usage
To use the class, create and destroy it's class in the normal way and anytime you wish to see how many instances are running, use the GetInstanceCount class method. For example:
TObjectCounter.GetInstanceCount
Test it out!
To test the above class, create a form with three buttons on it as follows:
type TForm1 = class(TForm) Create1: TButton; Create2: TButton; ShowCount: TButton; procedure Create1Click(Sender: TObject); procedure Create2Click(Sender: TObject); procedure ShowCountClick(Sender: TObject); private { Private declarations } public { Public declarations } end;
var Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Create1Click(Sender: TObject); var ObjectCounter: TObjectCounter; begin ObjectCounter := TObjectCounter.Create; end;
procedure TForm1.Create2Click(Sender: TObject); var ObjectCounter: TObjectCounter; begin ObjectCounter := TObjectCounter.Create; end;
procedure TForm1.ShowCountClick(Sender: TObject); begin ShowMessage(IntToStr(TObjectCounter.GetInstanceCount)); end;
end.
When you run this form, click the Show Count button first to see that our instance counter is initially set to 0 even before we create an object. Then press the Create 1 and Create 2 buttons multiple times to create several instances of the class and then click the Show Count button again to see the count.
Note: In this simple demo, we never free the object which, of course, is bad practice. However, it is just a proof of concept (POC).