Copy object data fields into subclass instance

2019-03-02 18:12发布

I have two class, TNode and TMaster. I subclassing TMaster from TNode.

The goal is to create a TMaster instance that contains all the data of a previously created TNode instance. Is there any 'built-in' method to achieve this, or it should be done manually?

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;

2条回答
\"骚年 ilove
2楼-- · 2019-03-02 18:56

It should be done manually.

Probably you want to implement something like Assign for TPersistent descendants. To make it work, you have to override Assign(To) routine, implementing deep field-by-field copying.

查看更多
forever°为你锁心
3楼-- · 2019-03-02 19:03

If I understand you correctly what you are trying is to implement data reusability. This can't be solved by class inheritance.

What class inheritance does is alow you to create classes which contain all functionality of parent class (without the need to copy the whole code of parent class) and then extend that functionality even further by intorducing new functionality in this new class. When such class is created fields all the fields from parent and child class are created.

In order to achieve what you want you should use two seperate classes which you would need to create independantly. First class should contain data which is common to all final classes. Second class contains aditional data and simply forwards the data of first class using properties so in the end it seems as it does contain data from both classes. in order to do this sucsessfully your second class should have referecne to the first class stored in it. Let me show you code example:

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;

Now you can acces to all data from both classes as if it would be stored in one.

NOTE: When using this approach you need to watch for certain things:

TCommonData class should always be created before other classes that forward its data. It should also be destroyed last.

If you alow other classes to change TCommonData data as in my code example and you are using multithreading you should take care of thread synchronization in order to avoid data damage. The easiest way to do is by adding a crictical exception in TCommonData SetSomeData procedure.

All classes should always read or write data from TCommonData through its properties and not by directly accessing its fields in order to alow thread synchronization method presented above to work.

Never in subsequent classes use

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

Always use getter/setter methods so you can add aditional check to avoid access violation which would occur if you try accesing common data before you have assigned external connection to common data class.

查看更多
登录 后发表回答