Autor Beitrag
Geri
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 78

XP
RAD Studio XE pro
BeitragVerfasst: Mi 12.08.09 11:31 
Hallo zusammen


Ich habe mehrere Klassen, welche von einander abgeleitet sind. Jede der Klasse wurde mit einem Copy-Constructor ausgesattet.
Nun habe ich in einer Liste Instanzen der verschiedenen Klassen und möchte eine Kopie der gesamten Liste erstellen

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
type
    TBaseClass = class
               mValue:Integer;
               constructor.create(aValue);overload;
               constructor.Create(aINstance:TBaseClass);overload;  // copy Konstruktor
            end;

    TClassB = class(TBaseClass)
               constructor.Create(aInstance:TBaseClass);overload// copy Konstruktor
            end;

    TClassC = class(TBaseClass)
               constructor.Create(aInstance:TBaseClass);overload;  // copy Konstruktor
            end;
   
var BaseList:Tlist;
    i:Integer;
    copyList:Tlist;
    Element:TBaseClass;
begin
  BaseList:=TList.Create();
  BaseList.add(TBaseClass.Create(123));
  BaseList.add(TClassB.Create(456));
  BaseList.add(TClassC.Create(789));
  ..

// und nun die Kopie der gesamten Liste erstellen
  CopyList:=TList.Create();
  for i:= 0 to BaseList.Count-1 do
  Begin
    Element:=BaseList[i]
    if Element.classtype = TBaseClass then CopyList.add(TBaseClass.Create(Element)) else
    if Element.classtype = TClassB then CopyList.add(TBaseB.Create(Element)) else
    if Element.classtype = TClassC then CopyList.add(TBaseC.Create(Element)) else
    Begin
      // error, unkown class
    end;
  end
End;


Gibt es vielleicht eine Möglichekeit die Abfrage der gesamten Klassen zu vermeiden und gleich den richtigen Constructor aufzurufen?

Etwas ähnliches wie vielleicht:
ausblenden Delphi-Quelltext
1:
   CopyList.Add((Element.ClassType).Creat(Element)) ???					

Fehlen mir evtl. in den Konstruktoren nur ein paar overrides :)?

Vielen Dank für ein paar hilfreiche Tipps im Voraus

Geri
Xentar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2077
Erhaltene Danke: 2

Win XP
Delphi 5 Ent., Delphi 2007 Prof
BeitragVerfasst: Mi 12.08.09 11:39 
Ich versteh noch nicht, was du machen willst, aber ich rate mal
ausblenden Delphi-Quelltext
1:
2:
3:
4:
for i := 0 to BaseList.Count - 1 do
begin
  CopyList.Add(BaseList[i]);
end;


Und was meinst du bitte mit "Copy-Konstruktor"?? Eine Klasse hat einen einzigen Konstruktor.. da wird nix gecopy'd. Was du meinen könntest, wäre Assign() ?

_________________
PROGRAMMER: A device for converting coffee into software.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19312
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mi 12.08.09 11:41 
Was ein Konstruktor mit Copy zu tun hat, verstehe ich jetzt nicht? Meinst du den Klassentyp "kopieren", also ein entsprechendes Objekt neu erstellen? Oder meinst du den Inhalt kopieren? Dann wäre Assign geeigneter.

Eine Möglichkeit wäre das Factory-Pattern. ;-)

Du kannst das zum Beispiel so machen, dass du eine ID übergibst, du kannst auch via class of und ggf. TClassList (Unit Contnrs) eine Liste von Klassen verwalten. Das geht z.B. so, dass sich die Klassen selbst praktisch anmelden in dieser Liste, oder dass diese Liste in initialization gefüllt und in finalization wieder freigegeben wird. Dann kannst du das auch in einer Schleife machen.
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Mi 12.08.09 11:43 
Copy-Constructors kommen aus der C++-Welt (was richtig nerviges dort). Etwas analoges unter Delphi erhälst Du mit Assign; vorausgesetzt, Assign ist für deine Klassen korrekt implementiert.

Zu deiner Frage, warum der Source nicht geht: Weil TClass die geforderte Methode nicht bereitstellt; da fehlt mindestens noch ein Typecast auf class of TBaseClass.

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
Reinhard Kern
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 591
Erhaltene Danke: 14



BeitragVerfasst: Mi 12.08.09 14:01 
user profile iconXentar hat folgendes geschrieben Zum zitierten Posting springen:

Und was meinst du bitte mit "Copy-Konstruktor"?? Eine Klasse hat einen einzigen Konstruktor..


Hallo,

ist mir noch nicht aufgefallen - eine Klasse von mir hat 9 Konstruktoren (einen für jeden verwalteten Datentyp) und funktioniert einwandfrei.

Und ein Konstruktor kann machen was er will, auch eine Kopie von einem anderen Objekt.

Gruss Reinhard
Geri Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 78

XP
RAD Studio XE pro
BeitragVerfasst: Mi 12.08.09 14:21 
Hallo zusammen

Vielen Dank für eure Tipps.

Unter einem "Copy-Constructor" verstehe ich einen Constructor, welcher als Parameter eine Referenz seiner BasisKlasse hat. Wird er aufgerufen, dann erzeugt er eine neue Instanz der Klasse und weist sich anschliessend selbst die Werte von aInstance zu.

z.B.
ausblenden Delphi-Quelltext
1:
2:
3:
Type
   TCLASSA = class
              constructor Create(aInstance:TCLASSA);



Ich möchte eine "echte" Kopie des Objektes erstellen. Analoger code findet man in Zeile 32 bis 34. Diese Methode funktioniert sehr gut, ist für den Fall des Kopierens aber etwas umständlich.

Schön wäre eben wenn man nicht zuerst herausfinden müsste um welche Klasse essich handelt:)

Beste Grüsse

Geri
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Mi 12.08.09 14:28 
Kopie erstellen über Assign realisieren. Oder mit Factory-Pattern kombinieren.

Alternativ statische Methode Clone anlegen und überall überschreiben (in den abgeleiteten Klassen)

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
Tilman
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1405
Erhaltene Danke: 51

Win 7, Android
Turbo Delphi, Eclipse
BeitragVerfasst: Mi 12.08.09 15:32 
user profile iconXentar hat folgendes geschrieben Zum zitierten Posting springen:
Eine Klasse hat einen einzigen Konstruktor.. da wird nix gecopy'd.


Mehrere Konstruktoren sind in Delphi ganz normal. Z.B. haben alle von TWinControl abgeleiteten Komponenten in der VCL schonmal mindestens 2, nämlich Create und CreateParented.

_________________
Bringe einen Menschen zum grübeln, dann kannst du heimlich seinen Reis essen.
(Koreanisches Sprichwort)
Geri Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 78

XP
RAD Studio XE pro
BeitragVerfasst: Mi 12.08.09 15:54 
@BenBe:
Wäre es nicht ein Stilbruch wenn man in einer Assign-Methode eine Instanz der entsprechenden Klasse erzeugen würde? Meiner Ansicht nach hat Assign doch lediglich die Aufgabe Werte zuzuweisen sondern nicht ein neues Objekt anzulegen...

Die Sache mit den Patterns habe ich mir noch nicht angeschaut....:)

Mit dem Hinweis von BenBe bin ich nun aber zu einer meiner nach "schönen" Lösung gekommen. Vielleicht auch für andere interessant.
Anbei der Code. Kritik und Lösungsalternativen werden gerne entgegengenommen.

Im Beispiel werden drei Klassen implementiert und für jede Klasse eine statische Clone-Methode. Es wird je ein Objekt der Klassen TBaseClass, TClassB und TClassC erzeugt und in einer Liste abgelegt. Anschliessend wird eine Clone der Liste (inkl. der abgelegeten Objekte) erstellt.

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
    TBaseClass = class
                  private
                    mValue:Integer;
                  public
                    constructor create(aValue:Integer);overload;
                    class Function clone(aInstance:TBaseClass):TBaseClass;virtual;
                  published
                    property Value:Integer read mValue write mValue;
                  end;

    TClassB = class(TBaseClass)
                    class Function clone(aInstance:TBaseClass):TBaseClass;override;
                  end;

    TClassC = class(TBaseClass)
                    class Function clone(aInstance:TBaseClass):TBaseClass;override;
                  end;


var
  Form1: TForm1;

implementation

{$R *.dfm}

constructor TBaseClass.Create(aValue:Integer);
Begin
  mValue:=aValue;
End;

class Function TBaseClass.Clone(aInstance:TBaseClass):TBaseClass;
Begin
  result:=TBaseClass.create(aInstance.mValue);
End;

class Function TClassB.Clone(aInstance:TBaseClass):TBaseClass;
Begin
  result:=self.create(aInstance.mValue);
End;

class Function TClassC.Clone(aInstance:TBaseClass):TBaseClass;
Begin
  result:=self.create(aInstance.mValue);
End;


procedure TForm1.Button1Click(Sender: TObject);
var BaseList:TList;
    CopyList:TList;
    i:Integer;
    Element:TBaseClass;
begin
  BaseList:=TList.Create();
  BaseList.add(TBaseClass.Create(123));
  BaseList.add(TClassB.Create(456));
  BaseList.add(TClassC.Create(789));
  CopyList:=TList.Create();
  for i:= 0 to BaseList.Count-1 do
  Begin
    Element:=BaseList[i];
    CopyList.Add(Element.clone(Element));
  end;

  for i:= 0 to copyList.Count - 1 do
  Begin
    Element:=CopyList[i];
    memo1.lines.add('Copy of class : ' + Element.ClassName + '   value ' + IntToStr(Element.mValue));
  End;

  while BaseList.count > 0 do
  begin
    Element:=BaseList[0];
    Element.Destroy();
    BaseList.delete(0);
  end;
  BaseList.Destroy();

  while CopyList.count > 0 do
  begin
    Element:=CopyList[0];
    Element.Destroy();
    CopyList.Delete(0);
  end;
  CopyList.Destroy();}
end;


Beste Grüsse

Geri