泛型无参数构造函数
问题描述:
有人可以解释为什么在下面的代码,class1List不不要求class1的有一个参数的构造函数,但class2list 确实需要等级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
,它的预期构造函数已被调用。因此编译器接受这个代码。需要注意的是早期版本的编译器会拒绝这个代码,并迫使你使用下面的投
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
构造,有可能的类将不能正确初始化。它准备从专用类型T
(如果存在)调用无参数构造函数,并且在声明泛型类型时应用constructor
约束。但是,该语言没有办法为接受参数的构造函数应用构造函数约束。
现在,您可以应用constructor
约束条件,但那样做没有用。为了正确地初始化实例,您需要使用参数调用构造函数。实际上,这意味着您应该使用虚拟构造函数的第一种方法。
不要试图走出这个洞。此代码将编译
Result := T(class2(T).Create(i));
但可能不会做你想做的。这将调用class2
的静态构造函数,这肯定不是你想要的。
有趣。谢谢你的解释。 – Dsm
'请注意早期版本的编译器'你会碰巧知道在哪个版本中修复了? – Johan
@Johan在XE7中需要演员阵容,我怀疑它可能在西雅图发生了变化,但我只是从这里的评论中知道这一点,并且我的记忆可能很容易出错 –