Base class contructor

I’ve problem with constructors.

Base class contructor is virtual.
The inherited class has override constructor.
Problem - without calling interited constructor in override it’s always called.

type
  TBaseClass = public class
  private
  protected
  public
    constructor; virtual;
  end;

  TClass = public class(TBaseClass)
  private
  protected
  public
    constructor; override;
  end;

implementation

constructor TBaseClass;
begin
  System.Windows.MessageBox.Show('aaa');
end;

constructor TClass;
begin
  System.Windows.MessageBox.Show('bbb');
end;

var vClass := new TClass(); - raises two MessageBox’es;

In other methods it works different - it works ok :slight_smile:

In .NET you are required to call the base class, so if you don’t, the compiler inserts an inherited call for you. Same goes for the JVM and Cocoa framework.

Is there any way to disable it?

No it’s a runtime requirement. What are you trying to accomplish?

In base class I’ve got a property - Command - TCommand and an Execute method for executing this command. Command is created in constructor - it works.
In inherited class I’ve got also Command property - TTestCommad - reintroduce and TTestCommand is created in constructor.

When I create inherited class and call Execute - it raises TCommand - not TTestCommand.

It’s all designed on interfaces.

You could use a virtual class method instead of a virtual constructor to get this behavior.

Yes - I’ve just done it, but then Command in base class is nil and Execute form base class raise exception.

I want to do it without overrideing Execute method

if you make the fields that should be set protected you can set them from a static method in the same/sub clas.

  TMainModel = public class(IMainModel)
  protected
    FCommand: IMainCommand;
  public
    method Execute; virtual;

    property Command: IMainCommand read FCommand write FCommand;
  end;

  TTestModel = public class(TMainModel, ITestModel)
  private
  protected
  public
    property Command: ITestCommand read FCommand write FCommand; reintroduce;
  end;

Type mismatch, cannot assign “IMainCommand” to “ITestCommand”

Of course

ITestCommand = public interface(IMainCommand)
end;

I could make getter and setter with casting for my type, but is thera any way without doing it?

If you can use a sub class for all types a generic can work:

IBaseCommand = public interface
end;
ISubCommand  = public interface(IBaseCommand )end; 
BaseModel<T> = public class where T: IBaseCommand;
public
  property Command: T;
end;

SubModel = public class(BaseCommand<ISubCommand>) end;

etc

Ok - ther will be getter and setter with casting :wink:

Thanks

Could you not simply decouple the initialisation of the Command reference from the constructor chain ? Make a virtual method for initialising the command object and call it when you need your first concrete reference to a command:

TBaseObject = class
private
   fCommand: ICommand;
protected
   function InitCommand: ICommand; virtual;
public
   procedure Execute; virtual;
end;

procedure TBaseObject.InitCommand: ICommand;
begin
   result := TBaseCommand.Create;
end;

procedure TBaseObject.Execute;
begin
   if NOT Assigned(fCommand) then
     fCommand := InitCommand;

   ...
end;

Then in your derived object class, override the InitCommand method to return an instance of the required command class:

TDerivedObject = class(TBaseObject)
private
   fDerivedCommand: IDerivedCommand;
protected
   function InitCommand: ICommand; override;
end;

function TDerivedObject.InitCommand: ICommand;
begin
  fDerivedCommand := TDerivedCommand.Create;

  result := fDerivedCommand;
end;

The TBaseObject class should not need to know about any new capabilities introduced by the IDerivedCommand interface - by definition the TBaseObject class knows only about IBaseCommand.

Similarly the IDerivedCommand interface should extend the IBaseCommand interface and TDerivedObject class needs only to retain an explictily typed reference to the IDerivedCommand interface if it makes use of those additional capabilities, otherwise it can continue to use the IBaseCommand reference (via a public or protected property on TBaseObject which provides that reference).

1 Like

Thank you for your answer :slight_smile: