【问题标题】:Copy object data fields into subclass instance将对象数据字段复制到子类实例中
【发布时间】:2014-05-28 07:34:48
【问题描述】:

我有两个类,TNode 和 TMaster。我从 TNode 继承了 TMaster。

目标是创建一个 TMaster 实例,其中包含先前创建的 TNode 实例的所有数据。是否有任何“内置”方法来实现这一点,或者应该手动完成?

type

  Tnode = class(TObject)
  private
    FSite: TSite;
    FhndNode: THandle; 
    FnodeID: word;
    FslaveID: longword; 
    FcoordX: double; 
    FcoordY: double;     
    FhndSubRect: THandle; 
    FdNodes: TdNodes; 
    Fdestinations: Tdestinations;
    FGroup: byte;
    FDomain: byte;
    FRFsense: byte; 
    FComm: byte; 
    FlcIDtextHnd: THandle; 
    ...
  public
    constructor create();
    ...
  end;

  TMaster = class(TNode);
  private
    FName: string;
    FIP: string; 
    FMAC: string;
  public
    constructor create( aHandle: HWND; aName, aIP, aMAC: string );
    procedure MSG_SETCONFIG( aNode: TNode; aSwitch: integer ); 
    property Name: string read FName write FName;
    property IP: string read FIP write FIP;
    property MAC: string read FMAC write FMAC;
  end;

【问题讨论】:

  • 在程序中我存储了很多Tnode实例,但只有一个TMaster实例,所以TNode不需要这些字段。
  • 你可以用 RTTI 做到这一点
  • @DavidHeffernan 谢谢你,但目前我不知道如何在这里利用 RTTI。 (:

标签: delphi object subclassing


【解决方案1】:

如果我对您的理解正确,您正在尝试实现数据可重用性。这不能通过类继承来解决。

类继承的作用是让您创建包含父类所有功能的类(无需复制父类的整个代码),然后通过在这个新类中引入新功能来进一步扩展该功能。当创建此类字段时,将创建父类和子类的所有字段。

为了实现你想要的,你应该使用两个单独的类,你需要独立创建它们。 第一类应该包含所有最终类共有的数据。 第二类包含附加数据,并使用属性简单地转发第一类的数据,因此最终它似乎包含来自两个类的数据。 为了成功地做到这一点,你的第二个班级应该参考存储在其中的第一个班级。 让我给你看代码示例:

type
  TCommonData = class(TObject)
  private
    FSomeData: Integer;
  protected
    procedure SetSomeData(AValue: Integer);
  public
    property SomeData: Integer read FSomeData write SetSomeData;
  end;

  TExtendedData = class(TObject);
  private
    FMoreData: Integer;
    //Common data
    FCommonData: TCommonData;
  protected
    procedure SetMoreData(AValue: Integer);
    //Common data
    procedure SetCommonData(AValue: TCommonData);
    function GetSomeData: Integer;
    procedure SetSomeData(AValue: Integer);
  public
    constructor Create(ACommonData: TCommonData);
    property MoreData: Integer read FMoreData write SetMoreData;
    //External data
    property CommonData: TCommonData read FCommonData write SetCommonData;
    property SomeData: Integer read GetSomeData write SetSomeData;
  end;

implementation

TCommonData.SetSomeData(AValue: Integer);
begin
  FSomeData := AValue;
end;

TExtendedData.Create(ACommonData: TCommonData);
begin
  //Assign external connection to common data object
  FCommonData := ACommonData;
end;

TExtendedData.SetMoreData(AValue: Integer);
begin
  FMoreData := AValue;
end;

TExtendedData.SetCommonData(AValue: TCommonData);
begin
  FCommonData := AValue;
end;

TExtendedData.GetSomeData: Integer;
begin
  //Check to see if external class conection has been assigned
  if FCommonData <> nil then
  begin
    result := FCommonData.SomeData;
  end
  //Set some uniqe result if no external connection has been assigned
  else result := -1; 
end;

TExtendeddata.SetSomedata(AValue: Integer);
begin
  //Check to see if external class conection has been assigned
  if FCommonData <> nil then
  begin
    FCommonData.SomeData := AValue;
  end
  else //Log error or raise Exception here
end;

现在您可以访问两个类中的所有数据,就好像它们存储在一个类中一样。

注意:使用此方法时,您需要注意以下事项:

TCommonData 类应始终在转发其数据的其他类之前创建。它也应该最后被销毁。

如果您在我的代码示例中允许其他类更改 TCommonData 数据并且您正在使用多线程,您应该注意线程同步以避免数据损坏。最简单的方法是在 TCommonData SetSomeData 过程中添加一个严重异常。

所有类都应始终通过其属性从 TCommonData 读取或写入数据,而不是直接访问其字段,以使上述线程同步方法起作用。

在以后的课程中永远不要使用

property Somedata: Integer read FCommonData:SomeData write FCommonData.SomeData;

始终使用 getter/setter 方法,以便您可以添加额外检查以避免访问冲突,如果您在将外部连接分配给公共数据类之前尝试访问公共数据,则会发生访问冲突。

【讨论】:

    【解决方案2】:

    应该手动完成。

    您可能想为TPersistent 后代实现类似Assign 的东西。要使其正常工作,您必须重写 Assign(To) 例程,实现逐个字段的深度复制。

    【讨论】:

    • +1 虽然您的回答与我的问题更相关,但我接受 SilverWarrior 的回答,因为我意识到他的解决方案对我来说已经足够了。谢谢!
    猜你喜欢
    • 2015-02-04
    • 1970-01-01
    • 1970-01-01
    • 2019-06-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-16
    • 1970-01-01
    相关资源
    最近更新 更多