[Delphi] Object copy

Pagina: 1
Acties:

  • ArieProductions
  • Registratie: Januari 2002
  • Laatst online: 27-11-2024
naar aanleiding hiervan:

[topic=307018/1/25]

Wat ik wil, is een exacte copy van een willekeurig object, inclusief alle 'onderliggende' objecten waarvan het object de eigenaar is. Onderstaande code is voorbeeldje wat niet gaat werken.
code:
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
type
  TRootObject = class(TObject)
  private
    FName: String;
    procedure SetName(const Value: String);

  public
    property Name : String read FName write SetName;
    constructor Create; Overload;
    constructor Create(aName : String); Reintroduce; Overload;

    destructor Destroy; Override;
  end;


  TForm1 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }

  public
    { Public declarations }
    Object1 : TRootObject;
  end;

.........


procedure TForm1.FormCreate(Sender: TObject);
begin
  Object1 := TRootObject.Create('Object1');
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  Object2 : TRootObject;
begin

  Object2 := TRootObject.Create('Object2');
  // eigenlijk wil ik een exacte copy maken van Object1.
  Object2 := Object1;
  // bovenstaande slaat dus nergens op maar geeft het idee aan

  // dit levert dus twee keer dezelfde Name op.
  Memo1.Lines.Add(Object1.Name);
  Memo1.Lines.Add(Object2.Name);

  // en dit gaat natuurlijk mis omdat Object2 = Object1
  // en die wordt al in de formdestroy weggeflikkerd.
  Object2.Destroy;

end;


procedure TForm1.FormDestroy(Sender: TObject);
begin
    Object1.Destroy; // gaat op deze manier fout...
end;

Volgens mij is het op te lossen door bij TRootObject een functie te maken die er voor zorgt dat er een exacte copie van zichzelf gemaakt kan worden.

bijvoorbeeld:
code:
1
2
3
4
5
function Copy: TRootObject;
begin
  Result:= TRootObject.Create(Object1.Name);
  // en hieronder de rest van de atrributen die gecopieerd moeten worden
end;

Iemand enig idee of dit gaat lukken.

edit:
taalfout

"Quidquid latine dictum sit, altum videtur" (Whatever is said in Latin sounds profound)


Verwijderd

code:
1
2
3
4
Object2 := TRootObject.Create('Object2');
// eigenlijk wil ik een exacte copy maken van Object1.
Object2 := Object1;
// bovenstaande slaat dus nergens op maar geeft het idee aan

Wat je hier doet is erg fout, je zegt tegen delphi dat er ruimte gemaakt moet worden voor een object... waarna je de pointer naar die ruimte als het ware weg gooit en je dus een geheugen lek hebt.... Hierdoor werkt je object.destroy ook niet meer...

Als het goed is zou het moeten werken simpel weg:
Object2 := Object1;

  • Kool
  • Registratie: September 1999
  • Niet online
Op dinsdag 26 maart 2002 15:51 schreef TimD het volgende:

Als het goed is zou het moeten werken simpel weg:
Object2 := Object1;
Object2 verwijst nu gewoon naar Object1. Je maakt geen kopie. Naar mijn weten is er geen methode aanwezig om een object volledig te kopieren.

  • ArieProductions
  • Registratie: Januari 2002
  • Laatst online: 27-11-2024
Op dinsdag 26 maart 2002 15:51 schreef TimD het volgende:

Als het goed is zou het moeten werken simpel weg:
Object2 := Object1;
Maar dan heb ik nog steeds geen 'exacte' copy, maar een object, met twee pointers er naar toe.

"Quidquid latine dictum sit, altum videtur" (Whatever is said in Latin sounds profound)


Verwijderd

Maak een nieuwe create aan..
constructor create(copyobject: TJouwObject);
self := copyobject;

Zo iets?

Verwijderd

De enige manier is alle properties te kopieren. Een nette manier is als volgt:

Gebruik niet TObject maar TPersistent als ancestor en override de method Assign. Dan krijg je:
code:
1
2
3
4
5
6
7
8
9
10
11
12
procedure TRootObject.Assign(Source: TPersistent);
begin
  // als source een rootobject is dan naam kopieren
  // anders doorgeven naar ancestor, misschien kan die er iets mee
  if Source is TRootObject then
  begin
    Name := TRootObject(Source).Name;
    // andere properties kopieren
  end
  else
    inherited Assign(Source);
end;

Kopie maak je dan met:
code:
1
2
  Object2 := TRootObject.Create;
  Object2.Assign(Object1);

Zo doen alle Dephi-componenten het. Zie de help over Assign voor meer info.

  • AdLentis
  • Registratie: Mei 2000
  • Laatst online: 27-10-2025

AdLentis

Gadget Inspector

Een alternatieve/extra manier is een "Copy-Constructor" toevoegen. Die kan zelf weer gebruik maken van de assign functie van TPersistent.
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
TObject1 = class(TPersistent)
public
  constructor Create;
  constructor Copy(Source: TObject1);
  // Blablabla
end;

constructor TObject1.Create;
begin
  // Blablabla
end;

constructor TObject1.Copy(Source: TObject1);
begin
  inherited Create;
  self.Assign(Source);
end;

Da's het zo ongeveer...

Ik ben tenminste niet altijd hypocriet!


  • Delphi32
  • Registratie: Juli 2001
  • Laatst online: 01:40

Delphi32

Heading for the gates of Eden

En als je in je destination object geen behoefte hebt aan de waarden van private/protected fields in je source object, ZOU je kunnen overwegen om published properties te maken en dan het kopieren over te laten aan een generieke TMyComponentCopier of zoiets :P
Heb zelf ooit iets dergelijks gemaakt voor een TObjectDataSet (om ervoor te zorgen dat ik TObjects in een TObjectDataSet kon stoppen, die dan weer middels TDataSource en standaard TDBxxx components op mn forms bruikbaar waren), en ik kan je vertellen dat het kan, maar dat het hier en daar verrekte lastig is. Maar van dit soort werk word ik O+

  • ArieProductions
  • Registratie: Januari 2002
  • Laatst online: 27-11-2024
Ik zal de volgende keer eens beginnen met TPersistent, voorlopig het volgende inelkaar gekleid:
code:
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
87
88
89
90
91
  TRootObject = class(TObject)
  private
    FName: String;
    procedure SetName(const Value: String);
    function Copy : TRootObject; OverLoad;
    procedure CopyData(Dest : TRootObject); OverLoad;
  public
    property Name : String read FName write SetName;
    constructor Create; Overload;
    constructor Create(aName : String); Reintroduce; Overload;

    destructor Destroy; Override;
  end;

  TRootObject2 = class(TRootObject)
  private
    FObject : TRootObject;
    function Copy : TRootObject2; OverLoad;
    procedure CopyData(Dest : TRootObject2); OverLoad;
  public
    constructor Create(aName : String); //Overload;
    destructor Destroy; Override;

  end;



{ TRootObject }

constructor TRootObject.Create;
begin
  inherited;
end;

function TRootObject.Copy: TRootObject;
begin
  Result := TRootObject.Create(FName);
end;

procedure TRootObject.CopyData(Dest: TRootObject);
begin
  Dest.Name := Name;
end;

constructor TRootObject.Create(aName: String);
begin
  inherited Create;
  Name := aName;
end;

destructor TRootObject.Destroy;
begin
  inherited;

end;

procedure TRootObject.SetName(const Value: String);
begin
  FName := Value;
end;


{ TRootObject2 }

function TRootObject2.Copy: TRootObject2;
begin
  Result := TRootObject2.Create(FName);
  CopyData(Result);
end;

procedure TRootObject2.CopyData(Dest: TRootObject2);
begin
  inherited CopyData(Dest);
  Dest.FObject := FObject.Copy;
end;

constructor TRootObject2.Create(aName: String);
begin
  inherited;
  FObject := TRootObject.Create('FObject');

end;

destructor TRootObject2.Destroy;
begin
  inherited;
  if FObject <> nil then
    FObject.Destroy;
   

end;

Nadeel hiervan is dat je bij ieder afgeleid Object een Copy en CopyData moet maken om te zorgen dat alle info meekomt.

"Quidquid latine dictum sit, altum videtur" (Whatever is said in Latin sounds profound)

Pagina: 1