Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Richtige Objekt-Kopie? Aber wie? (https://www.delphipraxis.net/86393-richtige-objekt-kopie-aber-wie.html)

Kedariodakon 13. Feb 2007 17:00


Richtige Objekt-Kopie? Aber wie?
 
Ok ich habe mal was ganz feines, wozu ich nicht gerade die passende Lösung parrat habe...

Ich habe verschiedene voneinander abgeleitete Klassen:

Delphi-Quellcode:
TParameterBase          = Class
//  ...
TParameter              = Class( TParameterBase )
//  ...
TParamererCollection    = Class( TParameterBase )
//  ...
TParameterCollectionList = Class( TParameterBase )
Von diesen Klassen gibt es, wer hätte es gedacht, weitere Ableitungen und dies verschieden tief...

Nun habe ich an einer Stelle ein Problem, dass ich eine Kopie eines Objekts benötige!

Als vorbereitende Maßnahme hab ich natürlich die Basisklasse "TParameterBase" mit einer virtuellen Assign-Methode versehen, welche auch fein durch alle Klassen gepflegt wurde.. =]

Problem ist aber, wie erzeuge ich ein Objekt einer Klasse, die ich im schlimmsten Fall nur über den "untersten" Vertreter "TParameterBase" kenne, um "Assign" aufzrufen?


Das dümmste was mir ATM einfällt, wäre die Basisklasse mit einer virtuellen "GetCopie" Methode auszustatten und diese überall nachzupflegen...
Nunja, ich halte diese Lösung aber für nicht so gut... ;)

Eventuell hat ja jemand einen viel viel besseren Vorschlag...


Bye Christian

uligerhardt 13. Feb 2007 17:17

Re: Richtige Objekt-Kopie? Aber wie?
 
Ich habe das für meine Kurven-Hierarchie mit Basisklasse TKurve so gelöst:
Delphi-Quellcode:
type
  TKurve = class(TPureInterfacedObject, IDrawable)
  private
    constructor CreateRaw; // nur fürs Klonen
    //...
  public
    //...
    function Clone: TKurve;
    procedure Assign(AKurve: TKurve); virtual;
    //...
  end;
Delphi-Quellcode:
constructor TKurve.CreateRaw;
begin
  inherited Create;
end;

function TKurve.Clone: TKurve;
type
  TKurvenClass = class of TKurve;
begin
  // Da der Konstruktor über ClassType aufgerufen wird (und nicht direkt
  // TKurve.CreateRaw), wird eine Instanz des richtigen Typs erzeugt:
  Result := TKurvenClass(ClassType).CreateRaw;
  Result.Assign(Self);
  Assert(Result.ClassType = ClassType);
end;
Vielleicht nützt dir das was.

Ciao, Uli.

Kedariodakon 14. Feb 2007 15:12

Re: Richtige Objekt-Kopie? Aber wie?
 
hmm ein ClassType.Create sollte doch allein schon ausreichen oder? Ich werd es mal testen. :cyclops:

Bye Christian

uligerhardt 14. Feb 2007 15:29

Re: Richtige Objekt-Kopie? Aber wie?
 
Zitat:

Zitat von Kedariodakon
hmm ein ClassType.Create sollte doch allein schon ausreichen oder?

Öhm, da könntest du sogar recht haben. :)

Kedariodakon 14. Feb 2007 16:19

Re: Richtige Objekt-Kopie? Aber wie?
 
Hmm die Klasse wird zwar erstellt, aber scheinbar ohne das der Constructor aufgerufen wird... :oops:

Was schlussendlich dazu führt, dass an ein paar Stellen baba passsiert...

Bye Christian

uligerhardt 14. Feb 2007 19:42

Re: Richtige Objekt-Kopie? Aber wie?
 
Bei nachfolgendem Testprojekt passiert bei mir kein Baba. (Wenn wir bei Baba an das Gleiche denken. :))

CloneAssignTest.dpr:
Delphi-Quellcode:
program CloneAssignTest;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  CloneAssign in 'CloneAssign.pas';

var
  b1, b2: TBasis;

begin
  b1 := TAbgeleitetS.Create('StringDing', 'Blah');
  try
    b2 := b1.Clone;
    Writeln(b1.ToString);
    Writeln(b2.ToString);
  finally
    b1.Free;
  end;

  b1 := TAbgeleitetI.Create('IntDing', 4711);
  try
    b2 := b1.Clone;
    Writeln(b1.ToString);
    Writeln(b2.ToString);
  finally
    b1.Free;
  end;

  Readln;
end.
CloneAssign.pas:
Delphi-Quellcode:
unit CloneAssign;

interface

type
  TBasis = class
  strict private
    FName: string;
  public
    constructor Create(const AName: string);
    function Clone: TBasis;
    procedure Assign(Source: TBasis); virtual;
    function ToString: string; virtual;
  end;

  TAbgeleitetS = class(TBasis)
  strict private
    FText: string;
  public
    constructor Create(const AName, AText: string);
    procedure Assign(Source: TBasis); override;
    function ToString: string; override;
  end;

  TAbgeleitetI = class(TBasis)
  strict private
    FCount: Integer;
  public
    constructor Create(const AName: string; ACount: Integer);
    procedure Assign(Source: TBasis); override;
    function ToString: string; override;
  end;

implementation

uses
  SysUtils;
 
{ TBasis }

constructor TBasis.Create(const AName: string);
begin
  inherited Create;
  FName := AName;
end;

function TBasis.Clone: TBasis;
begin
  // Da der Konstruktor über ClassType aufgerufen wird (und nicht direkt
  // TBasis.CreateRaw), wird eine Instanz des richtigen Typs erzeugt:
  Result := TBasis(ClassType.Create);
  Assert(Result.ClassType = ClassType);
  Result.Assign(Self);
end;

procedure TBasis.Assign(Source: TBasis);
begin
  FName := Source.FName;
end;

function TBasis.ToString: string;
begin
  Result := FName + ': ' + ClassName;
end;

{ TAbgeleitetS }

constructor TAbgeleitetS.Create(const AName, AText: string);
begin
  inherited Create(AName);
  FText := AText;
end;

procedure TAbgeleitetS.Assign(Source: TBasis);
begin
  inherited Assign(Source);
  FText := TAbgeleitetS(Source).FText;
end;

function TAbgeleitetS.ToString: string;
begin
  Result := inherited ToString + sLineBreak + ' Text = "' + FText + '"';
end;

{ TAbgeleitetI }

constructor TAbgeleitetI.Create(const AName: string; ACount: Integer);
begin
  inherited Create(AName);
  FCount := ACount;
end;

procedure TAbgeleitetI.Assign(Source: TBasis);
begin
  inherited Assign(Source);
  FCount := TAbgeleitetI(Source).FCount;
end;

function TAbgeleitetI.ToString: string;
begin
  Result := inherited ToString + sLineBreak + ' Count = ' + IntToStr(FCount);
end;

end.
Haut das bei dir auch hin?

marabu 14. Feb 2007 19:43

Re: Richtige Objekt-Kopie? Aber wie?
 
Hallo ihr beiden,

am Code von Uli sticht mir der statische Konstruktor ins Auge. Um auf TParameterBase aufbauende Klassen in einer Factory einsetzen zu können ist der virtuelle Konstruktor mit gleichbleibender Signatur gefragt. Hier nur grob skizziert - die Übertragung auf eine Methode statt einer stand-alone function dürfte nicht schwer fallen:

Delphi-Quellcode:
type
  TParameterBase = class
  public
    constructor Create; virtual;
  end;

  TParameter = class(TParameterBase)
  public
    constructor Create; override;
  end;

  TParameterBaseClass = class of TParameterBase;


function Clone(p: TParameterBase): TParameterBase;
begin
  Result := TParameterBaseClass(p.ClassType).Create;
  Result.Assign(p);
end;
Dass der gewünschte Konstruktor bei Christians Versuch mit ClassType.Create nicht ausgeführt wird liegt daran, dass mit diesem Aufruf nur der statische Konstruktor von TObject errreicht wird. Das sollte im direkten Vergleich mit dem Code aus meiner Beispiel-Funktion klar werden.

Freundliche Grüße vom marabu

uligerhardt 14. Feb 2007 21:09

Re: Richtige Objekt-Kopie? Aber wie?
 
Hallo, marabu!

Zitat:

Zitat von marabu
am Code von Uli sticht mir der statische Konstruktor ins Auge. Um auf TParameterBase aufbauende Klassen in einer Factory einsetzen zu können ist der virtuelle Konstruktor mit gleichbleibender Signatur gefragt.

Den muss ich dann aber auch in jeder Ableitung überschreiben, wo er dann jedesmal exakt nichts macht - laaaangweilig! :)

Zitat:

Zitat von marabu
Dass der gewünschte Konstruktor bei Christians Versuch mit ClassType.Create nicht ausgeführt wird liegt daran, dass mit diesem Aufruf nur der statische Konstruktor von TObject errreicht wird.

Klassenspezifische Initialisierung erledigt ja der Aufruf von Assign in TBasis.Clone. TObject.Create reicht also aus, solange ich ein "vernünftig" null-initialisiertes Objekt (also inkl. referenzgezählter Typen und so) des richtigen Typs kriege. Und das tut ClassType.Create auch bei statischem Konstruktor. (Oder genauer der Code, den der Compiler hinterrücks generiert, NewInstance oder _ClassCreate oder irgendsowas.) Anderenfalls würde das Assert(Result.ClassType = ClassType) fehlschlagen. Oder hab ich was übersehen?

Zugegebenermaßen kam mir mein Vorgehen am Anfang auch etwas wagemutig vor, aber es funktioniert seit einiger Zeit in einem realen Projekt.

Uli.

marabu 15. Feb 2007 07:12

Re: Richtige Objekt-Kopie? Aber wie?
 
Guten Morgen,

Zitat:

Zitat von uligerhardt
... Den muss ich dann aber auch in jeder Ableitung überschreiben ...

egal wer dir das erzählt hat - er wollte dich leimen. Du musst nicht, aber du kannst.

Zitat:

Zitat von uligerhardt
... Oder hab ich was übersehen? ...

Ich denke du hast das Wort Factory übersehen. Wenn dieses Konzept dich nicht interessiert, dann macht mein Beitrag für dich natürlich keinen Sinn. Christian wollte aber wissen, warum seine Konstruktoren nicht ausgeführt werden und das habe ich an Hand von deinem Code erklären wollen - no offense meant.

Freundliche Grüße


Alle Zeitangaben in WEZ +1. Es ist jetzt 03:26 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz