Entwickler-Ecke
Delphi Language (Object-Pascal) / CLX - Copy-Konstruktor
Geri - Mi 12.08.09 11:31
Titel: Copy-Konstruktor
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
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; 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 - 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() ?
jaenicke - 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 [
http://en.wikipedia.org/wiki/Factory_method_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 - 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.
Reinhard Kern - 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 - 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 - 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)
Tilman - 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.
Geri - 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.
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
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!