Generics without stepless constructors

Can someone explain why, in the code below, class1List does not require class1 to have a parameterless constructor, but class2list requires class2 to have a parameterless constructor.

unit Unit11;

interface

uses
  System.Generics.Collections;

type
  class1 = class
  public
    constructor Create( const i : integer ); virtual;
  end;

  class1List<T : class1 > = class( TObjectList< T > )
  public
    function AddChild( const i : integer ) : T;
  end;

  class2 = class
  public
    constructor Create( const i : integer );
  end;

  class2List<T : class2 > = class( TObjectList< T > )
  public
    function AddChild( const i : integer ) : T;
  end;


implementation

{ class1List<T> }

function class1List<T>.AddChild(const i: integer): T;
begin
  Result := T.Create( i );
  inherited Add( Result );
end;

{ class2List<T> }

function class2List<T>.AddChild(const i: integer): T;
begin
  Result := T.Create( i );
  inherited Add( Result );
end;

{ class1 }

constructor class1.Create(const i: integer);
begin

end;

{ class2 }

constructor class2.Create(const i: integer);
begin

end;

end.

      

+3


source to share


1 answer


function class1List<T>.AddChild(const i: integer): T;
begin
  Result := T.Create( i );
  inherited Add( Result );
end;

      

The constructor is class1

declared virtual

. Therefore, the compiler knows that it is T.Create

giving the instance T

for which the intended constructor was called. Hence the compiler accepts this code. Note that earlier versions of the compiler will reject this code and force you to use the following listing

Result := T(class1(T).Create( i ));

      

But later versions of the compiler removed the need for such trickery.


function class2List<T>.AddChild(const i: integer): T;
begin
  Result := T.Create( i );
  inherited Add( Result );
end;

      



A constructor is class2

not virtual

, so the compiler knows that if it were to call the constructor class2

, the class would probably not have been properly initialized. It is ready to call a parameterless constructor from a specialized type T

if it exists and you enforce the constraint constructor

when declaring a generic type. However, the language does not offer any application of constructor constraints for constructors that take parameters.

Now you can apply the constraint constructor

, but it won't do any good. To properly initialize the instance, you need to call the constructor with a parameter. This means that from a practical point of view, you should use the first approach, using a virtual constructor.

Don't be tempted to get out of this hole. This code will compile

Result := T(class2(T).Create( i ));

      

but most likely won't do what you want. This will call the static constructor class2

, which is definitely not what you want.

+4


source







All Articles