Delphi-PRAXiS
Seite 1 von 2  1 2   

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi Handling von Objekten (vom Typ TObject) (https://www.delphipraxis.net/116111-handling-von-objekten-vom-typ-tobject.html)

Yheeky 23. Jun 2008 19:33


Handling von Objekten (vom Typ TObject)
 
Hey,

so, neue Frage, neuer Thread ;-)

Ich beschäftige mich zur Zeit ein bisschen mit der Klasse TObject. Ich weiss jedoch leider noch nicht so recht wie genau man mit Objekten umgeht. Habe schon ein Tutorial gelesen, aber scheinbar mache ich hin und wieder etwas falsch, weil sich bei mir desöfteren Zugriffsverletzungen ereignen.
Unklar ist mir z.B. wann ich

Delphi-Quellcode:
Obj := TObject.Create;
benutze und wann ich einfach ohne oben angegebene Zeile

Delphi-Quellcode:
Obj := dummyFunction(getObj(Param));
verwende.

Ein paar grundlegende Infos wären super!

Danke schonmal! :-)

Christian Seehase 23. Jun 2008 19:40

Re: Handling von Objekten (vom Typ TObject)
 
Moin Christian,

im ersten Falle erzeugst Du das Objekt, und die Variable bekommt dann die Referenz auf die erzeugte Instanz, damit Du damit arbeiten kannst.

Mit dem zweiten Fall kann ich nichts anfangen :gruebel:

mkinzler 23. Jun 2008 19:41

Re: Handling von Objekten (vom Typ TObject)
 
TObject ist die Mutter aller Klassen. D.h. jede Klasse in Delphi erbt von ihr.

Delphi-Quellcode:
Obj := TObject.Create;
Erzeugt eine neue Instanz

Yheeky 23. Jun 2008 20:01

Re: Handling von Objekten (vom Typ TObject)
 
Okay, ein anderes Beispiel ;-)

Delphi-Quellcode:
var tempAuto : TAuto;
begin
tempAuto := TAuto.Create;
tempAuto := autoSammlung.GetAutoByName('Opel');

tempAuto.Free;
Erstens wurde mir gesagt, dass ich TAuto.Create; nicht ausführen muss, zweitens, dass ich es in der zweiten Zeile wieder überschreibe und drittens bekomme ich bei tempAuto.Free; eine Zugriffsverletzung.

Zu den Punkten:
1.) Warum muss ich es nicht immer ausführen, wenn es doch "die Mutter aller Klassen" ist?
2.) Warum überschreibe ich tempAuto hier? Ich dachte ich hätte über Create die Instanz erstellt und würde ihr in der zweiten Zeile einfach ein Objekt zuweisen.
3.) Warum kann ich das Objekt auf diese Weise nicht einfach freigeben?

So, das sind jetzt erstmal ein paar Fragen ;-)

OldGrumpy 23. Jun 2008 20:07

Re: Handling von Objekten (vom Typ TObject)
 
Wie schon oben gesagt, mit TObject.Create erzeugst Du eine neue Instanz - wenn Du das dreimal machst, hast Du am Ende drei eigenständige Objekte. Von denen muss auch jedes am Ende wieder abgeräumt werden (mittels FreeAndNil() oder TObject.Free, je nachdem, mein Tipp dazu: Verwende wo es geht FreeAndnil).

Der zweite Fall soll - vermute ich mal - das Weiterreichen einer Instanz symbolisieren. Dabei wird kein neues Objekt erzeugt, sondern nur eine Art Verweis auf ein bereits existierendes Objekt "nach draussen gereicht". Dieser Verweis, auch Pointer genannt, ermöglicht es Dir, von praktisch überall her auf das Objekt zuzugreifen.

Ganz wichtig: Wenn Du mit diesen Verweisen arbeitest, musst Du sehr genau hinschauen, wer das Objekt am Ende wieder freigeben darf! Wenn das Objekt freigegeben wird, hat das keine Auswirkungen auf den Pointer, jedoch wird ein Zugriff über den Pointer auf das bereits abgeräumte Objekt meist mit einer Zugriffsverletzung "belohnt". Je nach Programm kann auch zuerst *anscheinend* alles glatt gehen, aber im Speicher kann dabei ziemliches Chaos angerichtet werden, was früher oder später das Programm zum Absturz bringt - oder zumindest zu seltsamem Verhalten bringt.

Eine überall gültige Regel, welche Seite das Objekt, auf das der Pointer zeigt, wieder freigeben darf, gibt es nicht. In der Regel sagt man aber, wer es angelegt hat, sollte es auch wieder abräumen. Ausnahmen sind zum Beispiel Objekte, die zwar "auf der einen Seite" erzeugt werden, dann aber nur auf der "anderen Seite" benutzt werden. Hier macht es Sinn, das Objekt dann auch auf "der anderen Seite" abzuräumen wenn es nicht mehr benötigt wird.

//EDIT: Roter Kasten :)

Nachtrag: Ohne TAuto zu kennen, können diese Fragen nicht beantwortet werden, da die Antworten von der Implementation von TAuto abhängen.

mkinzler 23. Jun 2008 20:10

Re: Handling von Objekten (vom Typ TObject)
 
Zitat:

1.) Warum muss ich es nicht immer ausführen, wenn es doch "die Mutter aller Klassen" ist?
Delphi-Quellcode:
tempAuto := autoSammlung.GetAutoByName('Opel');

Gibt eine Referenz auf eine vorhandenes Objekt zurück. Deshalb ist der Konstruktoraufruf überflüssig, denn sonst hättest du ja eine leere Instanz zuviel.
Zitat:

2.) Warum überschreibe ich tempAuto hier? Ich dachte ich hätte über Create die Instanz erstellt und würde ihr in der zweiten Zeile einfach ein Objekt zuweisen.
Es handelt sich bei tempAuto um eine Referenz-Variable ( Zeiger)
Zitat:

3.) Warum kann ich das Objekt auf diese Weise nicht einfach freigeben?
Das Objekt wird ja vom Objekt autoSammlung verwaltet

Khabarakh 23. Jun 2008 20:46

Re: Handling von Objekten (vom Typ TObject)
 
Zitat:

Zitat von Yheeky
2.) Warum überschreibe ich tempAuto hier? Ich dachte ich hätte über Create die Instanz erstellt und würde ihr in der zweiten Zeile einfach ein Objekt zuweisen.

Um es nochmal deutlich zu machen: Instanz und Objekt bedeuten dasselbe! Du weist der Variablen also ein neues Objekt zu und in der nächsten Zeile wieder eins. Damit ist das erste im Speicher-Nirvana: Es gibt keine Referenz mehr darauf, also kann es nicht mehr freigegeben werden.

Christian Seehase 23. Jun 2008 21:45

Re: Handling von Objekten (vom Typ TObject)
 
Moin Zusammen,

und um das von den anderen schon gesagte noch zu ergänzen:
Um solche Probleme zu umgehen, sollte man nie Objekte als Rückgabewert einer Funktion verwenden, da dann immer das Problem besteht, die Freigabe korrekt zu positionieren.
So wäre es übersichtlicher:

Delphi-Quellcode:
var
  tempAuto : TAuto;

begin
  tempAuto := TAuto.Create;
  try
    // Das Objekt, bzw. die Instanz mit Daten füllen
    autosammlung.GetAutoByName('Opel',tempAuto);
    // mit dem Objekt (tempAuto) arbeiten
    //...
  finally
    tempAuto.Free;
    // oder
    FreeAndNil(tempAuto);
  end;
end;

// So könnte dann die Methode deklariert werden.
// Statt eines Results vom Typ TAuto, wird eine Instanz von TAuto übergeben
procedure TAutoSammlung.GetAutoByName(const AsTyp : string;const AResult : TAuto);
begin
  // Hier nun die Daten holen und in AResult ablegen
  // Ein Create darf hier nicht mehr erfolgen!
  // AResult ist als const deklariert, damit man nicht versehentlich
  // eine weitere Instanz zuweist.
end;
Es gibt zwar auch Methoden, die ein Objekt zurückgeben (z.B. TListView.Add gibt ein Objekt vom Typ TListItem zurück), aber in diesem Falle verwaltet auch die Klasse (hier TListView) selber die Objekte (TListItem).
Solange man das nicht selber auch so macht, und die Objektinstanzen einzeln erzeugt, sollte man keine Objekt als Ergebnis zurückgeben (wie weiter oben schon erwähnt).

dominikkv 23. Jun 2008 22:03

Re: Handling von Objekten (vom Typ TObject)
 
Du musst dir ein Object, wenn du es so deklarierst
Delphi-Quellcode:
var
  MyObj: TMyObject;
so vorstellen:

- Du hast erstmal ein Speicherbereich (Heap), auf dem die ganzen Eigenschaften (Felder) gespeichert werden
- Außerdem hast du einen Zeiger auf diesen Bereich

Am Anfang ist nur der Zeiger da, der halt irgendwo hin zeigt (NIL - Not In List). Dieser Zeiger wird am Anfang der Procedure erstellt und am Ende der Procedure wieder gelöscht.
Um jetzt mit dem Objekt arbeiten zu können musst du dir erstmal dein Speicherbereich auf dem Heap reservieren und den Zeiger darauf setzen. Das erledigst du mit dem sogenannten Konstructor:
Delphi-Quellcode:
MyObj := TMyObject.Create;
Das ist immer zwingend notwendig, wenn du auf einen Zeiger zugreifst der nirgendwohin zeigt gibts ne Zugriffsverletzung.
Jetzt kannst du dir zB ein Object erstellen und mehrere Zeiger darauf haben:
Delphi-Quellcode:
var
  MyObj1, MyObj2: TMyObject;
begin
  MyObj1 := TMyObject.Create; // Speicherplatz reservieren und Zeiger MyObj1 ausrichten
  MyObj2 := MyObj1; // Auch noch den 2ten Zeiger ausrichten


  MyObj2.Eigenschaft := 'Bla';
  MyObj1.Eigenschaft := 'Hallo';
  Showmessage(MyObj2.Eigenschaft); // Da wir auf den gleichen Speicherbereich zugreifen kommt "Hallo"
  MyObj2.Free; // Den reservierten Speicherplatz wieder freigeben

  TMyObject.Create; // auch das ist möglich, blöderweise haben wir dann kein zeiger darauf -.-
end;
Das .free nicht vergessen, da der reservierte Speicherbereich sonst im Heap bleibt und erst am Ende, wenn das Programm beendet wird, freigegeben wird (-> Speicherleck).

Bei deiner oben genannten Funktion werden nur die Zeiger weitergegeben, da diese Zeiger schon auf einen Speicherbereich zeigen musst du in diesem Fall den Konstructor und Destructor (free) weglassen.
Nochmal ganz konkret: Mit dem Konstructor reservierst du Speicher und setzt deinen Zeiger darauf, bei deiner Funktion ist der Speicher schon da und du veränderst nur den Zeiger.

Yheeky 23. Jun 2008 22:56

Re: Handling von Objekten (vom Typ TObject)
 
Jungs, ihr seid super! Dank euren Beispielen glaube ich den Großteil verstanden zu haben. Ich hoffe ich kann´s nun in meinem Programm richtig benutzen :-)
DANKE!


Alle Zeitangaben in WEZ +1. Es ist jetzt 00:05 Uhr.
Seite 1 von 2  1 2   

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