Hide the utter "Create" constructor of TObject in Delphi

In Delphi, constructors can be inherited; this doesn’t happen in Java, C# and C++ for example. Furthermore, constructors in Delphi can have multiple and different names; usually they are called Create, but this is just a convention, since you can define a constructor with whatever name you choose.

In addition to all this, all classes in Delphi inherit ultimately from TObject, which contains a public parameterless constructor, named Create.

Due to the facts above, it‘s easy to understand that all classes in Delphi have a public Create parameterless constructor, that has been inherited from TObject.

I am not going to discuss here whether this is bad or good. What I want to show you is a way to hide the public Create parameterless constructor of TObject in case you need to do so.

Burn this out: you cannot hide any member (field, method, constructor, destructor) in Delphi by decreasing the level of visibility. If a member in a superclass is public, you cannot hide it in a child class by changing the visibility to protected or private. Once public you are always public. This means, you cannot hide the public Create parameterless constructor of TObject by lowering its visibility in an inheriting class.

So, how can we hide the Create constructor of TObject? Is there even a way for doing so? Yes, there is a way. We came to the solution in the LinkedIn’s Delphi Professionals group. I thought it would be worthy to share this with the rest of the Delphi community.

Basically, you can hide the public Create parameterless constructor of TObject with another public method having the same Create name. For example:

Class definition snipped:

TSomeClass = class(TObject)
public
//this constructor takes two parameters, and hides the TObject.Create()
constructor Create(aParameter1: string; aParameter2: Integer );
end;

Consuming code snipped:

var
  SomeObject: TSomeClass;
begin
  SomeObject:= TSomeClass.Create; //This does not compile!

  //This compiles. Uncomment and try...
  // SomeObject:= TSomeClass.Create('Hello People!', 12);

  try
    //TODO
  finally
    SomeObject.Free;
  end;
end;

See, in the code above the TObject.Create() has been hidden :-)

There is another consideration though: What happens if we overload the Create constructor?

TSomeClass = class(TObject)
public
  //this one takes two parameters, and hides the TObject.Create()
  constructor Create(aParameter1: string; aParameter2: Integer ); overload;
  constructor Create(aThisTakesAChar: Char); overload;
  constructor Create(aThisTakesAnInteger: Integer); overload;
end;

By overloading the Create constructor we have made the TObject.Create() visible again. If we want to keep it hidden, then we should avoid overloading. For that, you can simply use a different name for the new constructors being added. Something like this:

TSomeClass = class(TObject)
public
  //this one takes two parameters, and hides the TObject.Create()
  constructor Create(aParameter1: string; aParameter2: Integer );
  constructor Create2(aThisTakesAChar: Char);
  constructor Create3(aThisTakesAnInteger: Integer);
end;

Now the TObject.Create() constructor is hidden again.

Consuming code:

var
  SomeObject: TSomeClass;
begin
  SomeObject:= TSomeClass.Create; //This does not compile!

  //This compiles. Uncomment and try...
  // SomeObject:= TSomeClass.Create('Hello People!', 12);

  //This compiles. Uncomment and try...
  // SomeObject:= TSomeClass.Create1('H');

  //This compiles. Uncomment and try...
  // SomeObject:= TSomeClass.Create2(12);

  try
    //TODO
  finally
    SomeObject.Free;
  end;
end;

Why would someone want to hide the TObject.Create() anyway? It depends on the situation. I have found this very useful when implementing a singleton class in Delphi. For details refer to: Singleton class in Delphi.

As a conclusion, you can hide the TObject.Create() constructor by defining a new public method with the name Create in the inheriting class. You cannot hide TObject.Create() by lowering the visibility to protected, private, etc.

1 comment: