1
votes

Yet another in my series of questions regarding constructors in Delphi.

i have a base class that has has the virtual constructor:

TComputer = class(TObject)
public
    constructor Create(Teapot: Integer); virtual;
end;

The constructor is virtual for the times that someone needs to call

var
   computerClass: class of TComputer;
   computer: TComputer;
begin     
   computer := computerClass.Create(nTeapot);

The constructor is overridden in descendants:

TCellPhone = class(TComputer) 
public
   constructor Create(Teapot: Integer); override;
end;

TiPhone = class(TCellPhone ) 
public
   constructor Create(Teapot: Integer); override;
end;

Where TCellPhone and TiPhone descendants each have their opportunity to do their own initialization (of members not included for readability).

But now i add an overloaded constructor to some ancestor:

TCellPhone = class(TComputer) 
public
   constructor Create(Teapot: Integer); override; overload;
   constructor Create(Teapot: Integer; Handle: string); overload;
end;

The alternate constructor in TCellPhone calls the other virtual constructor, so it always gets the proper overridden behaviour:

constructor TCellPhone.Create(Teapot: Integer; Handle: string);
begin
   TCellPhone.Create(Teapot); //call sibling virtual constructor

   FHandle := Handle;
end;

The problem is that the descendant, overridden, constructor is never called. The actual stack trace chain of calls is:

phone := TiPhone.Create(37, 'spout')
   constructor TCellPhone.Create(Teapot: Integer; Handle: string)
      constructor TCellPhone.Create(Teapot: Integer)
         constructor TComputer.Create(Teapot: Integer)
            TObject.Create

The sibling call to TCellPhone.Create(int), which is virtual, should have called the descendant, overridden, method in TiPhone:

phone := TiPhone.Create(37, 'spout')
   constructor TCellPhone.Create(Teapot: Integer; Handle: string)
      constructor TiPhone.Create(Teapot: Integer)
         constructor TCellPhone.Create(Teapot: Integer)
            constructor TComputer.Create(Teapot: Integer)
               TObject.Create

So it seems that attempts to use a sibling virtual constructor is Delphi do not work as expected.

Is it then a bad idea for one constructor to use another? Is the design intention that code in overloaded constructors be copy-paste versions of each other?

i notice in .NET that some constructors chain to each other:

public Bitmap(int width, int height) : this(width, height, PixelFormat.Format32bppArgb) {}

public Bitmap(int width, int height, PixelFormat format) {...}

This only seems to be a problem if:

  • a constructor is virtual
  • you overload the constructors

Is the rule that you cannot have one constructor overload another?

1

1 Answers

8
votes

Errr..

constructor TCellPhone.Create(Teapot: Integer; Handle: string);
begin
   TCellPhone.Create(Teapot); //call sibling virtual constructor

   FHandle := Handle;
end;

That should be:

constructor TCellPhone.Create(Teapot: Integer; Handle: string);
begin
   Create(Teapot); //call sibling virtual constructor

   FHandle := Handle;
end;

You were just creating a new TCellphone instance and not calling the other Create method.