TMyBaseClass=class
constructor(test:integer);
end;
TMyClass=class(TMyBaseClass);
TClass1<T: TMyBaseClass,constructor>=class()
public
FItem: T;
procedure Test;
end;
procedure TClass1<T>.Test;
begin
FItem:= T.Create;
end;
var u: TClass1<TMyClass>;
begin
u:=TClass1<TMyClass>.Create();
u.Test;
end;
如何使用整数参数创建类。解决方法是什么?
答案 0 :(得分:11)
只是对正确的类进行类型转换:
type
TMyBaseClassClass = class of TMyBaseClass;
procedure TClass1<T>.Test;
begin
FItem:= T(TMyBaseClassClass(T).Create(42));
end;
将构造函数设置为虚拟也是个好主意。
答案 1 :(得分:2)
<强>更新强>
除了一种情况外,@ TOndrej提供的解决方案远远优于我在下面所写的内容。如果您需要对要创建的类进行运行时决策,那么下面的方法似乎是最佳解决方案。
我已经刷新了我对自己的代码库的记忆,这也解决了这个问题。我的结论是,你试图实现的目标是不可能的。如果有人想要迎接挑战,我会很高兴被证明是错误的。
我的解决方法是让通用类包含FClass
类型的字段class of TMyBaseClass
。然后我可以使用FClass.Create(...)
调用我的虚拟构造函数。我在断言中测试FClass.InheritsFrom(T)
。这一切都令人沮丧地非一般。正如我所说,如果有人能够证明我的信仰是错误的,我会投票,删除和欢欣!
在您的设置中,解决方法可能如下所示:
TMyBaseClass = class
public
constructor Create(test:integer); virtual;
end;
TMyBaseClassClass = class of TMyBaseClass;
TMyClass = class(TMyBaseClass)
public
constructor Create(test:integer); override;
end;
TClass1<T: TMyBaseClass> = class
private
FMemberClass: TMyBaseClassClass;
FItem: T;
public
constructor Create(MemberClass: TMyBaseClassClass); overload;
constructor Create; overload;
procedure Test;
end;
constructor TClass1<T>.Create(MemberClass: TMyBaseClassClass);
begin
inherited Create;
FMemberClass := MemberClass;
Assert(FMemberClass.InheritsFrom(T));
end;
constructor TClass1<T>.Create;
begin
Create(TMyBaseClassClass(T));
end;
procedure TClass1<T>.Test;
begin
FItem:= T(FMemberClass.Create(666));
end;
var
u: TClass1<TMyClass>;
begin
u:=TClass1<TMyClass>.Create(TMyClass);
u.Test;
end;
如果可能的话,另一个更优雅的解决方案是使用无参数构造函数,并在T
的虚拟方法中传递额外信息,可能称为Initialize
。
答案 2 :(得分:2)
您可以考虑为基类提供一个显式的初始化方法,而不是使用构造函数:
TMyBaseClass = class
public
procedure Initialize(test : Integer); virtual;
end;
TMyClass = class(TMyBaseClass)
public
procedure Initialize(test : Integer); override;
end;
procedure TClass1<T>.Test;
begin
FItem:= T.Create;
T.Initialize(42);
end;
当然,只有基类和所有子类都在您的控制之下,这才有效。
答案 3 :(得分:0)
似乎在Delphi XE中工作,首先调用T.Create,然后调用特定于类的Create作为方法。这类似于Rudy Velthuis(删除)的答案,尽管我没有介绍重载的构造函数。如果T是TControl或类似的类,这个方法似乎也能正常工作,所以你可以用这种方式构造可视化控件。
我无法在Delphi 2010上进行测试。
type
TMyBaseClass = class
FTest: Integer;
constructor Create(test: integer);
end;
TMyClass = class(TMyBaseClass);
TClass1<T: TMyBaseClass, constructor> = class
public
FItem: T;
procedure Test;
end;
constructor TMyBaseClass.Create(test: integer);
begin
FTest := Test;
end;
procedure TClass1<T>.Test;
begin
FItem := T.Create; // Allocation + 'dummy' constructor in TObject
try
TMyBaseClass(FItem).Create(42); // Call actual constructor as a method
except
// Normally this is done automatically when constructor fails
FItem.Free;
raise;
end;
end;
// Calling:
var
o: TClass1<TMyClass>;
begin
o := TClass1<TMyClass>.Create();
o.Test;
ShowMessageFmt('%d', [o.FItem.FTest]);
end;
答案 4 :(得分:0)
type
TBase = class
constructor Create (aParam: Integer); virtual;
end;
TBaseClass = class of TBase;
TFabric = class
class function CreateAsBase (ConcreteClass: TBaseClass; aParam: Integer): TBase;
class function CreateMyClass<T: TBase>(aParam: Integer): T;
end;
TSpecial = class(TBase)
end;
TSuperSpecial = class(TSpecial)
constructor Create(aParam: Integer); override;
end;
class function TFabric.CreateAsBase(ConcreteClass: TBaseClass; aParam: Integer): TBase;
begin
Result := ConcreteClass.Create (aParam);
end;
class function TFabric.CreateMyClass<T>(aParam: Integer): T;
begin
Result := CreateAsBase (T, aParam) as T;
end;
// using
var
B: TBase;
S: TSpecial;
SS: TSuperSpecial;
begin
B := TFabric.CreateMyClass <TBase> (1);
S := TFabric.CreateMyClass <TSpecial> (1);
SS := TFabric.CreateMyClass <TSuperSpecial> (1);