delphi - 为什么 Delphi 在动态对象创建期间调用错误的构造函数?

标签 delphi dynamic

我在动态对象创建期间调用了不正确的虚拟 Create() 方法时遇到了问题。调用父方法而不是子方法。

我已经查看了这些帖子,但无法弄清楚:
Delphi - Create class from a string

Exploring TRTTIType and Descendants

Can I pass a Class type as a procedure parameter

这里Class_References

我有以下类(class):

TCellObj = class(TPhysicsObj)
  ...
  public
    constructor Create(RgnMgr : TObject); virtual; //RgnMgr should be TRgnManager
    destructor Destroy;
    ...
  end;

  TCellObjClass = Class of TCellObj;

--------------------------------

 TCellTrialAObj = class(TCellObj)
    ...
    public
      ...
      constructor Create(RgnMgr : TObject); virtual; //RgnMgr should be TRgnManager
  end;
--------------------------------

TRgnManager = class (TObject)
  ... 
  public
    function NewCell(ClassRef : TCellObjClass) : TCellObj; 
    ...
  end;

  ....

  function TRgnManager.NewCell(ClassRef : TCellObjClass) : TCellObj;
  var CellObj : TCellObj;

  begin
    CellObj := ClassRef.Create(Self);
    CellObj.DefaultInitialize;
    CellObj.Color := TAlphaColors.Slategray;
    FCellsList.Add(CellObj);  //This will own objects.
    SetSelection(CellObj);
    Result := CellObj;
  end;

最后,我通过以下行开始动态对象创建过程:

RgnManager.NewCell(TCellTrialAObj);

我的目标是让 TRgnManager.NewCell 根据作为参数传入的派生类创建 TCellObj 的任何后代。我将在使用过程中将结果类型转换为适当的类类型。

当我在 NewCell 中使用调试器单步执行代码时,评估/修改工具告诉我 ClassRef = TCellTrialAObj 正如预期的那样。

但是当我进入 ClassRef.Create(self) 行时,它会转到 TCellObj.Create(),而不是我所期望的 TCellTrialAObj.Create() 。这是我不明白的部分。

将结果分配给 CellObj 后,评估/修改工具告诉我 CellObj.ClassName = 'TCellTrialAObj';

那么ClassRef就是TCellTrialAObj,那为什么Create()函数没有调用TCellTrialAObj.Create()呢??

提前致谢。

附注我正在使用 Embarcadero® Delphi 10 西雅图版本 23.0.22248.5795

附录

我使用上面链接中的示例拼凑了下面的这个函数。它似乎有效,并根据需要调用 TCellTrialAObj.Create。但我不明白到底是如何做的、为什么做的,或者我是否真的做对了。谁能解释一下吗?

  function TRgnManager.NewCell(ClassRef : TCellObjClass) : TCellObj;
  var CellObj : TCellObj;
      RT : TRttiType;
      C : TRttiContext;
      T : TRttiInstanceType;
      V : TValue;

  begin
    C := TRttiContext.Create;
    T := (C.GetType(ClassRef) as TRttiInstanceType);
    V := T.GetMethod('Create').Invoke(T.metaClassType,[self]);
    C.Free;
    CellObj := V.AsObject as TCellObj;

    //CellObj := ClassRef.Create(Self);
    CellObj.DefaultInitialize;
    CellObj.Color := TAlphaColors.Slategray;
    FCellsList.Add(CellObj);  //This will own objects.
    SetSelection(CellObj);
    Result := CellObj;
  end;

最佳答案

编译器警告将帮助您解决这个问题。您可能会注意到,在编译时收到警告Method 'Create' hides virtual method of base type 'TCellObj'。这是因为您已将后代 TCellTrialAObj 的构造函数声明为 virtual,而我们却推断您希望它覆盖

这里有一个最小的示例演示了您想要的功能。

program Project1;

{$APPTYPE CONSOLE}

type
  TCellObj = class
    public
      constructor Create; virtual;
  end;

  TCellObjClass = Class of TCellObj;

  TCellTrialAObj = class(TCellObj)
    public
      constructor Create; override;
  end;

constructor TCellObj.Create;
begin
  WriteLn('TCellObj');
end;

constructor TCellTrialAObj.Create;
begin
  WriteLn('Calling base constructor...');
  inherited;
  WriteLn('...and now in TCellTrialAObj constructor');
end;

function NewCell(ClassRef : TCellObjClass) : TCellObj;
var
  CellObj : TCellObj;
begin
  CellObj := ClassRef.Create;;
  Result := CellObj;
end;

var
  LCellObj : TCellObj;
begin
  LCellObj := NewCell(TCellTrialAObj);
  ReadLn;
end.

顺便说一句,您在这里使用注释来建议类型限制:

 constructor Create(RgnMgr : TObject); virtual; //RgnMgr should be TRgnManager

但是,可以对 TRgnMgr 类进行前向声明,并在稍后对其进行完全定义,从而允许您包含更强大的正式类型限制。

  TRgnMgr = class;  { Declare type... }

  TCellObj = class
    public
      constructor Create(RgnMgr : TRgnMgr); virtual;
  end;

  TCellObjClass = Class of TCellObj;

  TCellTrialAObj = class(TCellObj)
    public
      constructor Create(RgnMgr : TRgnMgr); override;
  end;

  TRgnMgr = class  { but define it later }
    private
      FFoo : integer;
  end;

关于delphi - 为什么 Delphi 在动态对象创建期间调用错误的构造函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44165088/

相关文章:

go - 如何通过字符串名称和字符串结构名称调用方法?

delphi - 如何按第一个数字对列表进行排序?

delphi - 如何从 TRichEdit 控件中完全删除选择栏?

delphi - 如何对 TComboBox 进行编程更改以与 LiveBindings 配合良好?

java - 将动态 Javascript 树结构加载到 JSP 中

jQuery on() 无法删除元素

delphi - delphi tlist对象方法调用

delphi - 将使用 Png 图像的项目转换为 D2009

java - 从另一个 Java 文件动态编译和运行 Hadoop 作业

css - Angular动态组件——添加Class等属性