Delphi 如何创建类的新实例?

Delphi 如何创建类的新实例?,delphi,delphi-2009,rtti,Delphi,Delphi 2009,Rtti,我有一个各种类实例的列表。我需要能够创建一个类的新实例,而不知道要创建什么。所有涉及的对象都有相同的祖先。对象成员变量的实际复制很容易…我遇到问题的地方是新对象的创建 诚然,我可以这样做: case MyObjectTypeInstance.MyTypeEnum of obj1: Result:=TObjectType1.Create; obj2: Result:=TObjectType2.Create; obj3: Result:=TObjectType

我有一个各种类实例的列表。我需要能够创建一个类的新实例,而不知道要创建什么。所有涉及的对象都有相同的祖先。对象成员变量的实际复制很容易…我遇到问题的地方是新对象的创建

诚然,我可以这样做:

case MyObjectTypeInstance.MyTypeEnum of
  obj1:
    Result:=TObjectType1.Create;

  obj2:
    Result:=TObjectType2.Create;

  obj3:
    Result:=TObjectType3.Create;
end;
type
  TAncestor = class;
  TAncestorClass = class of TAncestor;
  TAncestor = class 
  public
    constructor Create; virtual;

    class function CreateClass(const AId: string): TAncestor;
    class procedure RegisterClass(const AId: string; const AType: TAncestorClass);
  end;


class function TAncestor.CreateClass(const AId: string): TAncestor;
var
  atype : TAncestorClass;
begin
  atype := GetAncestorClass(AId);
  if atype<>nil then
    Result := atype.Create
  else
    Result := nil;
end;

class procedure TAncestor.RegisterClass(const AId: string; 
  const AType: TAncestorClass);
begin
  SetAncestorClass(AId, AType); // Link id to class type
end;
这不符合“开放/封闭原则”

起初,我认为我可以做一些类似“Result:=MyObjectTypeInstance.Create;”的事情,但由于析构函数的困难,这并没有达到预期的效果

这是我应该怎么做的最新猜测

var
  fooA, fooB:TFoo;
begin
  fooA:=TFoo2.Create;    // it could be any of many types

  fooB:=?  // how to create fooB of same class type as fooA????

  // do something

  fooA.Free;
  fooB.Free;
end;
我本以为这会更容易


谢谢你的帮助

选项1-创建名称/类映射列表:

选项2-使用“of class”变量

type
  TBaseObj = class
  end;

  TObjA = class(TBaseObj)
  end;

  TBaseObjClass = class of TBaseObj;

var
  objCls: TBaseObjClass;
  obj: TBaseObj;

objCls := TObjA;
obj := objCls.Create;
//obj is of type TObjA

选项1-创建名称/类映射列表:

选项2-使用“of class”变量

type
  TBaseObj = class
  end;

  TObjA = class(TBaseObj)
  end;

  TBaseObjClass = class of TBaseObj;

var
  objCls: TBaseObjClass;
  obj: TBaseObj;

objCls := TObjA;
obj := objCls.Create;
//obj is of type TObjA

如果所有类都有一个共同的祖先,则可以执行以下操作:

case MyObjectTypeInstance.MyTypeEnum of
  obj1:
    Result:=TObjectType1.Create;

  obj2:
    Result:=TObjectType2.Create;

  obj3:
    Result:=TObjectType3.Create;
end;
type
  TAncestor = class;
  TAncestorClass = class of TAncestor;
  TAncestor = class 
  public
    constructor Create; virtual;

    class function CreateClass(const AId: string): TAncestor;
    class procedure RegisterClass(const AId: string; const AType: TAncestorClass);
  end;


class function TAncestor.CreateClass(const AId: string): TAncestor;
var
  atype : TAncestorClass;
begin
  atype := GetAncestorClass(AId);
  if atype<>nil then
    Result := atype.Create
  else
    Result := nil;
end;

class procedure TAncestor.RegisterClass(const AId: string; 
  const AType: TAncestorClass);
begin
  SetAncestorClass(AId, AType); // Link id to class type
end;
类型
TAncestor=类;
TAncestorClass=TAncestor的类别;
TAncestor=类
公众的
构造函数创建;事实上的
类函数CreateClass(const-AId:string):TAncestor;
类过程寄存器类(const-AId:string;const-AType:TAncestorClass);
结束;
类函数TAncestor.CreateClass(const-AId:string):TAncestor;
变量
atype:TAncestorClass;
开始
atype:=GetAncestorClass(AId);
如果没有,那么
结果:=atype.Create
其他的
结果:=无;
结束;
类过程TAncestor.RegisterClass(const-AId:string;
常数类型:TAncestorClass);
开始
SetAncestorClass(辅助,AType);//链接id到类类型
结束;

您可以使用任何类型的标识进行类型注册。只要它们是独一无二的

如果所有类都有一个共同的祖先,您可以这样做:

case MyObjectTypeInstance.MyTypeEnum of
  obj1:
    Result:=TObjectType1.Create;

  obj2:
    Result:=TObjectType2.Create;

  obj3:
    Result:=TObjectType3.Create;
end;
type
  TAncestor = class;
  TAncestorClass = class of TAncestor;
  TAncestor = class 
  public
    constructor Create; virtual;

    class function CreateClass(const AId: string): TAncestor;
    class procedure RegisterClass(const AId: string; const AType: TAncestorClass);
  end;


class function TAncestor.CreateClass(const AId: string): TAncestor;
var
  atype : TAncestorClass;
begin
  atype := GetAncestorClass(AId);
  if atype<>nil then
    Result := atype.Create
  else
    Result := nil;
end;

class procedure TAncestor.RegisterClass(const AId: string; 
  const AType: TAncestorClass);
begin
  SetAncestorClass(AId, AType); // Link id to class type
end;
类型
TAncestor=类;
TAncestorClass=TAncestor的类别;
TAncestor=类
公众的
构造函数创建;事实上的
类函数CreateClass(const-AId:string):TAncestor;
类过程寄存器类(const-AId:string;const-AType:TAncestorClass);
结束;
类函数TAncestor.CreateClass(const-AId:string):TAncestor;
变量
atype:TAncestorClass;
开始
atype:=GetAncestorClass(AId);
如果没有,那么
结果:=atype.Create
其他的
结果:=无;
结束;
类过程TAncestor.RegisterClass(const-AId:string;
常数类型:TAncestorClass);
开始
SetAncestorClass(辅助,AType);//链接id到类类型
结束;

您可以使用任何类型的标识进行类型注册。只要它们是独一无二的

您可能需要创建一个抽象工厂或工厂方法类。这些都是常见的经过测试和验证的开发范例。

您可能需要创建一个抽象工厂或工厂方法类。这些都是经过测试和验证的常见开发范例。

谢谢大家的回答

dar7yl的解决方案非常适合我的需要

type
  TFoo = class
  private
    { private declarations }
  public
    { public declarations }
    class function MakeAnother:TFoo;
  end;

  TFoo1 = class(TFoo)
  private
    { private declarations }
  public
    { public declarations }
  end;

  TFoo2 = class(TFoo)
  private
    { private declarations }
  public
    { public declarations }
  end;

var
  fooA, fooB:TFoo;
begin
  fooA:=TFoo2.Create;
  foob:=fooA.MakeAnother;

  // do something here

  fooA.Free;
  fooB.Free;
end;

{ TFoo }

class function TFoo.MakeAnother: TFoo;
begin
  Result:=Create;
end;

谢谢大家的回答

dar7yl的解决方案非常适合我的需要

type
  TFoo = class
  private
    { private declarations }
  public
    { public declarations }
    class function MakeAnother:TFoo;
  end;

  TFoo1 = class(TFoo)
  private
    { private declarations }
  public
    { public declarations }
  end;

  TFoo2 = class(TFoo)
  private
    { private declarations }
  public
    { public declarations }
  end;

var
  fooA, fooB:TFoo;
begin
  fooA:=TFoo2.Create;
  foob:=fooA.MakeAnother;

  // do something here

  fooA.Free;
  fooB.Free;
end;

{ TFoo }

class function TFoo.MakeAnother: TFoo;
begin
  Result:=Create;
end;

另一个messier版本使用“类型类”和TObject.ClassType

type
 TFoo = class
  private
    { private declarations }
  public
    { public declarations }
    constructor Create(WhatEver : Integer);virtual;// just to show need for params
  end;

  TFooClass = class of TFoo;

  TFoo1 = class(TFoo)
  private
    { private declarations }
  public
    { public declarations }
    constructor Create(WhatEver : Integer);override;// just to show need for params
  end;

  TFoo2 = class(TFoo)
  private
    { private declarations }
  public
    { public declarations }
  end;


{$R *.dfm}

procedure TForm10.Button1Click(Sender: TObject);
var
  fooA, fooB:TFoo;

begin
  fooA:=TFoo2.Create(0);
  fooB:= TFooClass(FooA.ClassType).Create(1);

  // do something here

  fooA.Free;
  fooB.Free;

end;

{ TFoo }

constructor TFoo.Create(WhatEver: Integer);
begin
  ShowMessageFmt('%s %d', [Self.ClassName, WhatEver]);
end;

{ TFoo1 }

constructor TFoo1.Create(WhatEver: Integer);
begin
  inherited;

end;

另一个messier版本使用“类型类”和TObject.ClassType

type
 TFoo = class
  private
    { private declarations }
  public
    { public declarations }
    constructor Create(WhatEver : Integer);virtual;// just to show need for params
  end;

  TFooClass = class of TFoo;

  TFoo1 = class(TFoo)
  private
    { private declarations }
  public
    { public declarations }
    constructor Create(WhatEver : Integer);override;// just to show need for params
  end;

  TFoo2 = class(TFoo)
  private
    { private declarations }
  public
    { public declarations }
  end;


{$R *.dfm}

procedure TForm10.Button1Click(Sender: TObject);
var
  fooA, fooB:TFoo;

begin
  fooA:=TFoo2.Create(0);
  fooB:= TFooClass(FooA.ClassType).Create(1);

  // do something here

  fooA.Free;
  fooB.Free;

end;

{ TFoo }

constructor TFoo.Create(WhatEver: Integer);
begin
  ShowMessageFmt('%s %d', [Self.ClassName, WhatEver]);
end;

{ TFoo1 }

constructor TFoo1.Create(WhatEver: Integer);
begin
  inherited;

end;

谢谢你,野猫!事实上,感谢您对StackOverflow的巨大贡献。谢谢您Gamecat!事实上,谢谢你对StackOverflow的巨大贡献。谢谢你,gabr!事实上,谢谢你对StackOverflow的巨大贡献。谢谢你,gabr!事实上,感谢您对StackOverflow的巨大贡献。感谢您发布此问题/示例的后续信息——这对“有类似问题的潜伏者和“后来者”非常有帮助。”:)不客气。我总是很感激看到这样的后续行动,所以我试着自己去做!嗯,如果这就是你现在的解决方案,那么看来我一定误解了这个问题,然后。。。在我看来,您仍然明确指定要创建哪个类…我需要同一对象的另一个实例。也许我的问题不太好。谢谢你发布这个问题/例子的后续文章——这对“有类似问题的潜伏者和“后来者”非常有帮助。”:)不客气。我总是很感激看到这样的后续行动,所以我试着自己去做!嗯,如果这就是你现在的解决方案,那么看来我一定误解了这个问题,然后。。。在我看来,您仍然明确指定要创建哪个类…我需要同一对象的另一个实例。也许我的问题不是很好。我不会说它凌乱,但相当灵活:)我最近用它来创建克隆函数,基类可以在其中创建正确的子类实例。我认为这是真正的Delphi方法。只需确保构造函数是虚拟的。请注意,您必须编写TFooClass(FooA.ClassType).Create而不是FooA.Create的原因是后者不会分配新对象-这是Delphi调用继承构造函数的方式!我不认为它凌乱,但相当灵活:)我最近用它来创建克隆函数,基类可以在其中创建正确的子类实例。我认为这是真正的Delphi方法。只需确保构造函数是虚拟的。请注意,您必须编写TFooClass(FooA.ClassType).Create而不是FooA.Create的原因是后者不会分配新对象-这是Delphi调用继承构造函数的方式!