Autor |
Beitrag |
Geri
      
Beiträge: 78
XP
RAD Studio XE pro
|
Verfasst: 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
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; end;
TClassB = class(TBaseClass) constructor.Create(aInstance:TBaseClass);overload; end;
TClassC = class(TBaseClass) constructor.Create(aInstance:TBaseClass);overload; 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)); ..
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 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:
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
      
Beiträge: 2077
Erhaltene Danke: 2
Win XP
Delphi 5 Ent., Delphi 2007 Prof
|
Verfasst: Mi 12.08.09 11:39
Ich versteh noch nicht, was du machen willst, aber ich rate mal
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
      
Beiträge: 19312
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: 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
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: 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
      
Beiträge: 591
Erhaltene Danke: 14
|
Verfasst: Mi 12.08.09 14:01
Xentar hat folgendes geschrieben : |
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 
      
Beiträge: 78
XP
RAD Studio XE pro
|
Verfasst: 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.
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
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: 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
      
Beiträge: 1405
Erhaltene Danke: 51
Win 7, Android
Turbo Delphi, Eclipse
|
Verfasst: Mi 12.08.09 15:32
Xentar hat folgendes geschrieben : | 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 
      
Beiträge: 78
XP
RAD Studio XE pro
|
Verfasst: 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.
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
|
|