【问题标题】:How can i create a new instance of a class?如何创建一个类的新实例?
【发布时间】:2009-04-16 17:48:07
【问题描述】:

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

诚然,我可以这样做:

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

  obj2:
    Result:=TObjectType2.Create;

  obj3:
    Result:=TObjectType3.Create;
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;

我以为这会更容易!

感谢您的帮助!

【问题讨论】:

    标签: delphi delphi-2009 rtti


    【解决方案1】:

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

    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;
    

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

    【讨论】:

    • 谢谢游戏猫!事实上,感谢您对 StackOverflow 的巨大贡献。
    【解决方案2】:

    选项 1 - 创建名称/类映射列表:Is there a way to instantiate a class by its name in delphi?

    选项 2 - 使用“类”变量。

    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
    

    【讨论】:

    • 谢谢你!事实上,感谢您对 StackOverflow 的巨大贡献。
    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

      谢谢大家的回答!

      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;
      

      【讨论】:

      • 感谢您发布对您的问题/示例的后续跟进 - 对“有类似问题的潜伏者和'后来者'”非常有帮助。 :)
      • 不客气。我总是很高兴看到这样的后续行动,所以我尝试自己做!
      • 嗯,如果这是您的解决方案现在的样子,那么看来我一定误解了这个问题......在我看来,您仍然明确指定要创建哪个类......跨度>
      • 我需要同一对象的另一个实例。也许我的问题不是很好。
      【解决方案5】:

      另一个更混乱的版本是使用“类型类”和 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;
      

      【讨论】:

      • 不会称之为混乱,而是相当灵活 :) 我最近用它来创建克隆函数,其中基类能够创建正确的子类实​​例。
      • 我认为这是真正的 Delphi 方式。只要确保将构造函数设为虚拟即可。请注意,您必须编写 TFooClass(FooA.ClassType).Create 而不是 FooA.Create 的原因是后者不会分配新对象 - 这是 Delphi 调用继承构造函数的方式!
      猜你喜欢
      • 2016-08-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-10
      • 2015-01-01
      • 1970-01-01
      • 2022-07-21
      • 1970-01-01
      相关资源
      最近更新 更多