没有无参数构造函数的泛型
Generics without parameterless constructors
有人可以解释为什么在下面的代码中,class1List 不 要求 class1 有一个无参数的构造函数,但是 class2list 是否 要求 class 2 具有无参数构造函数。
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.
function class1List<T>.AddChild(const i: integer): T;
begin
Result := T.Create( i );
inherited Add( Result );
end;
class1
的构造函数声明为 virtual
。因此编译器知道 T.Create
产生一个 T
的实例,其预期的构造函数已被调用。因此编译器接受这个代码。请注意,早期版本的编译器会拒绝此代码并强制您使用以下 cast
Result := T(class1(T).Create( i ));
但较新版本的编译器已不再需要此类技巧。
function class2List<T>.AddChild(const i: integer): T;
begin
Result := T.Create( i );
inherited Add( Result );
end;
class2
的构造函数不是 virtual
,因此编译器知道如果它调用 class2
的构造函数,可能 class 不会正确初始化。它准备从专用类型 T
调用无参数构造函数(如果存在),并且在声明泛型类型时应用 constructor
约束。但是,该语言无法为接受参数的构造函数应用构造函数约束。
现在,您可以应用 constructor
约束,但这没有用。为了正确初始化实例,您需要使用参数调用构造函数。这意味着,实际上,您应该使用第一种使用虚拟构造函数的方法。
不要试图跳出这个洞。此代码将编译
Result := T(class2(T).Create( i ));
但可能不会如您所愿。这将调用 class2
的静态构造函数,这肯定不是您想要的。
有人可以解释为什么在下面的代码中,class1List 不 要求 class1 有一个无参数的构造函数,但是 class2list 是否 要求 class 2 具有无参数构造函数。
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.
function class1List<T>.AddChild(const i: integer): T;
begin
Result := T.Create( i );
inherited Add( Result );
end;
class1
的构造函数声明为 virtual
。因此编译器知道 T.Create
产生一个 T
的实例,其预期的构造函数已被调用。因此编译器接受这个代码。请注意,早期版本的编译器会拒绝此代码并强制您使用以下 cast
Result := T(class1(T).Create( i ));
但较新版本的编译器已不再需要此类技巧。
function class2List<T>.AddChild(const i: integer): T;
begin
Result := T.Create( i );
inherited Add( Result );
end;
class2
的构造函数不是 virtual
,因此编译器知道如果它调用 class2
的构造函数,可能 class 不会正确初始化。它准备从专用类型 T
调用无参数构造函数(如果存在),并且在声明泛型类型时应用 constructor
约束。但是,该语言无法为接受参数的构造函数应用构造函数约束。
现在,您可以应用 constructor
约束,但这没有用。为了正确初始化实例,您需要使用参数调用构造函数。这意味着,实际上,您应该使用第一种使用虚拟构造函数的方法。
不要试图跳出这个洞。此代码将编译
Result := T(class2(T).Create( i ));
但可能不会如您所愿。这将调用 class2
的静态构造函数,这肯定不是您想要的。