![]() |
Unterschied zwischen (var AFileStream: TFileStream) und (AFileStream: TFileStream)
Hallo zusammen
Irgendwie verstehe ich den Unterschied nicht, wenn ein Stream mit und ohne VAR als Parameter übergeben wird. Nach meinem Verständnis wird mit VAR die selbe Adresse des Objekts übergeben und ohne VAR nur eine Kopie des Objektes (somit eine andere Adresse) übergeben. Wenn ich aber im XE5 Debugger die Adresse vergleiche vom Objekt welches OHNE VAR übergeben wird und vom Parameter der aufgeruften Methode, dann sind die Adressen die selbben, auch wenn ich nicht VAR verwendet habe. Wenn ich den selben Aufruf der Mothode mit VAR im Parameter habe, dann sind die Adressen auch die gleichen. Was habe ich da missverstanden? Danke im Voraus! |
AW: Unterschied zwischen (var AFileStream: TFileStream) und (AFileStream: TFileStream
Nichts.
Änderungen am Inhalt von 'VAR'-Parametern werden nach außen mitgeteilt. Ohne 'VAR' bleibt die Veränderung des Inhaltes transparent, d.h. nichts geht nach außen. WIE das vom Compiler umgesetzt wird, ist nebensächlich. Klar, er könnte eine Kopie übergeben, aber wenn in der Routine nie etwas verändert wird, war die Kopie überflüssig. Ergo würde vielleicht ein Referenzzähler, oder ein Lazy-Copy mehr bringen, d.h. es wird die Originaladresse übergeben, aber beim ersten Ändern wird eine Kopie angelegt. Bei einfachen Datentypen wird bei ohne VAR der Wert direkt übergeben, mit Var die Adresse. Einfaches Beispiel:
Delphi-Quellcode:
Und für Objekte gilt: VAR nur dann, wenn die Instanz umgebogen wird.
Procedure Foo (Bar : Integer);
Begin Bar := Bar + 1; End; Procedure FooWithVar (Var Bar : Integer); Begin Bar := Bar + 1; End; ... n := 1; Foo(n); // die '1' wird auf den Stack gepackt, und logischerweise 'n' nicht verändert Assert(n = 1); FooWithVar(n); // Die Adresse von 'n' wird auf den Stac gepackt und so kann der Inhalt von 'n' verändert werden Assert(n = 2);
Delphi-Quellcode:
Das Problem beim Objekt-Parameter-VAR ist doch: Wer ist hier eigentlich zuständig für das Freigeben? Normalerweise gilt ja: Der, der die Instanz erzeugt, gibt sie auch wieder frei (produziert sauberen Code). Aber hier ist das nicht klar, wer das macht bzw. wer zuständig ist. Ergo: Finger weg, brauchste nicht.
Procedure ChangeTheStream (Var aStream : TStream);
Begin aStream := TMyStream.Create(); End; ... // Autschn. Speicherleck. theStream := TFileStream.Create... ChangeTheStream (theStream); Assert (theStream is TMyStream); |
AW: Unterschied zwischen (var AFileStream: TFileStream) und (AFileStream: TFileStream
|
AW: Unterschied zwischen (var AFileStream: TFileStream) und (AFileStream: TFileStream
Ich glaube, eine (halbwegs) ausführliche Antwort ist besser, auch zum Verständiss anderer, die hier nachlesen.
Zudem beantwortet die Erklärung im Wiki die Frage auch nicht: Zitat:
Zitat:
|
AW: Unterschied zwischen (var AFileStream: TFileStream) und (AFileStream: TFileStream
Zitat:
Delphi-Quellcode:
so bekommt das Label einen neuen Wert, ist ja klar, wenn man sich vor Augen hält, daß hier die Adresse von einem Label übergeben wird und nicht das Label oder eine neue Instanz des Labels.
procedure Zeigwas(const wert:string ;Lb:Tlabel);
begin lb.caption:=wert; end; Ob das alles allerdings so ganz sauber und im Sinne des Erfinders ist:gruebel: Gruß K-H |
AW: Unterschied zwischen (var AFileStream: TFileStream) und (AFileStream: TFileStream
Es gibt call by value, call by reference und const parameter.
Ein kleiner Test zeigt die Unterschiede
Delphi-Quellcode:
Die Ausführung ergibt dann
program dp_180328;
{$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils; type TTest = class end; procedure Output( const AContext : string; AInstance : TTest ); begin if Assigned( AInstance ) then Writeln( AContext, ': ', Integer( AInstance ) ) else Writeln( AContext, ': NIL' ) end; procedure CallByValue( AInstance : TTest ); begin AInstance := TTest.Create; Output( 'CallByValue', AInstance ); end; procedure CallByReference( var AInstance : TTest ); begin AInstance := TTest.Create; Output( 'CallByReference', AInstance ); end; procedure Call( const AInstance : TTest ); begin // Auskommentiert, da es hier einen Compiler-Fehler gibt! // AInstance := TTest.Create; // Output( 'Call', AInstance ); end; procedure Main; var LTest : TTest; begin LTest := TTest.Create; try Output( 'Main', LTest ); CallByValue( LTest ); Output( 'Main', LTest ); CallByReference( LTest ); Output( 'Main', LTest ); Call( LTest ); Output( 'Main', LTest ); finally LTest.Free; end; end; begin try Main; except on E : Exception do Writeln( E.ClassName, ': ', E.Message ); end; ReadLn; end.
Code:
Main : 31925952
CallByValue : 31925968 Main : 31925952 CallByReference: 31925984 Main : 31925984 Main : 31925984 |
AW: Unterschied zwischen (var AFileStream: TFileStream) und (AFileStream: TFileStream
Mit dem CONST, VAR und OUT bestimmt man nur, ob der "Inhalt" der Variable verändert werden kann.
Bei einem Integer ist das der Zahlenwert, aber bei einem Objekt ist der nur der interne Instanz-Zeiger. Ohne VAR kann man keine Andere Instanz eines Objektes zurückgeben, aber der "Inhalt" des Objektes ist davon nicht betroffen. Prinzipiell wird der "Inhalt" aller Pointer-Objekte nicht beeinflusst. Außer bei Strings (AnsiString, WideString und UnicodeString, ausgeschlossen den ShortStrings, welche ja wie Records reagieren), denn dort sorgt der Compiler für eine Prüfung und "verbietet" Schreibzugriffe, wenn der Parameter CONST ist und ansonsten sorgt der Compiler dort für die entsprechende Behandlung, indem der Inhalt automatisch "umkopiert" wird, bei einem Schreibzugriff. |
AW: Unterschied zwischen (var AFileStream: TFileStream) und (AFileStream: TFileStream
Wenn man weiß was bei einer Instanz übergeben wird (nur eine Referenz, quasi eine Visitenkarte), dann versteht man auch die Delphi-Dokumentation.
Mit dem
Delphi-Quellcode:
wird die gleiche Visitenkarte (Referenz) übergeben. Bemale ich die, dann ist die bemalt.
var
Ohne dem
Delphi-Quellcode:
wird eine Kopie der Visitenkarte (Referenz) übergeben. Bemale ich die, dann ist eben diese Kopie bemalt und das Original bleibt unverändert.
var
Mit dem
Delphi-Quellcode:
wird die Visitenkarte (Referenz) als unbemalbares Objekt (Read-Only) übergeben und kann gar nicht bemalt werden.
const
|
AW: Unterschied zwischen (var AFileStream: TFileStream) und (AFileStream: TFileStream
Keiner hat die Frage wirklich verstanden, ergo hat sie auch keiner wirklich beantwortet. Ist übrigens eine Frage, die ich mir vor langer Zeit auch mal stellte und dann einfach beschloß "ist halt so":
Ich nehme einen
Delphi-Quellcode:
und öffne eine Datei.
TFileStream
Nun rufe ich eine Methode auf, und übergebe diesen Stream als Parameter. In dieser Methode wird nun per
Delphi-Quellcode:
-Methode des
Seek
Delphi-Quellcode:
an das Ende der Datei gesprungen.
TFileStreams
Es ist echt schnurzpiepegal, ob ich den TFileStream als
Delphi-Quellcode:
,
CONST
Delphi-Quellcode:
oder auch normal übergebe, die Seek-Methode verschiebt den Dateizeiger ans Ende der Datei. Ergo verändere ich doch den
VAR
Delphi-Quellcode:
(wenigstens seinen Dateizeiger !), was doch dem
TFileStream
Delphi-Quellcode:
widerspricht.
CONST
Ich habe das irgendwann einfach so akzeptiert, das CONST nicht vollständig auf Objekte wirkt. |
AW: Unterschied zwischen (var AFileStream: TFileStream) und (AFileStream: TFileStream
Du änderst nur Eigenschaften des Streams, aber nicht den Stream (also die übergebene Instanz) selbst. Das wäre aber möglich, wenn man ihn als Var-Parameter übergibt, und kann zu sehr hässlichen Nebenwirkungen führen, wenn man nicht weiß, was man da tut. Ein Negativbeispiel findet sich z.B.
![]() |
AW: Unterschied zwischen (var AFileStream: TFileStream) und (AFileStream: TFileStream
@OlafSt
Wenn ich dir meinen Schlüssel zu meiner Wohnung gebe, dann kannst du in die Wohnung rein und dort umräumen. Tauscht du den Schlüssel nun aus und gibts mir diesen zurück, komme ich nicht mehr in meine Wohnung.
Delphi-Quellcode:
Gebe ich dir eine Kopie meines Schlüssels, dann kannst du immer noch in die Wohnung rein und umräumen.
procedure Foo( var AKey : TWohnung );
Da ich aber keinen Schlüssel von dir zurücknehme, kann ich trotzdem noch mit meinem Schlüssel in meine Wohnung (und sehe dann entweder Chaos oder endlich mal eine aufgeräumte Wohnung)
Delphi-Quellcode:
procedure Foo( AKey : TWohnung );
|
AW: Unterschied zwischen (var AFileStream: TFileStream) und (AFileStream: TFileStream
...oder eine leere wohnung :lol:
Ich persönlich habe das ganze ja schon länger verstanden (auch wenn ich der Ansicht bin, das CONST nun mal CONST ist, auch Eigenschaften sollten dann unveränderlich sein). Ich hoffe, der TE bekam nun seine Antwort ;) |
AW: Unterschied zwischen (var AFileStream: TFileStream) und (AFileStream: TFileStream
Zitat:
(Es wird ja gar nicht die Instanz übergeben, nur der Weg, wie ich dort hinkomme und bei
Delphi-Quellcode:
kann ich den Weg auch gar nicht ändern)
const
|
AW: Unterschied zwischen (var AFileStream: TFileStream) und (AFileStream: TFileStream
Zitat:
Besser kann man es nicht erklären. :thumb: Da solltest du dir ein Patent drauf geben lassen. |
AW: Unterschied zwischen (var AFileStream: TFileStream) und (AFileStream: TFileStream
Zitat:
Sir Rufo hat es genau richtig beschrieben.:idea: |
AW: Unterschied zwischen (var AFileStream: TFileStream) und (AFileStream: TFileStream
Zitat:
Wenn ich an der Kopie des Schlüssels etwas ändere (Eigenschaft: Farbe, oder Form), dann ist bei
Delphi-Quellcode:
dann ist doch auch der Original-Schlüssel geändert, richtig?
procedure Foo( AKey : TKey );
Gibt es eine Möglichkeit (gibt es überhaupt Situationen) wo das Objekt vollkommen als Kopie übergeben wird?? Ist das Verhalten in .Net das selbe? |
AW: Unterschied zwischen (var AFileStream: TFileStream) und (AFileStream: TFileStream
Zitat:
In .NET ist das Verhalten soweit ich weiß das selbe. |
AW: Unterschied zwischen (var AFileStream: TFileStream) und (AFileStream: TFileStream
Danke an alle schon Mal :-)
Ich habe verstanden wie sich ein Objekt als Parameter verhaltet :-) Ziel erreicht! |
AW: Unterschied zwischen (var AFileStream: TFileStream) und (AFileStream: TFileStream
Zitat:
Es wird eben nicht die Instanz übergeben, sondern eine Referenz/Zeiger/Pointer (wie auch immer du das definieren willst) auf die Instanz. Zitat:
Und selbst wenn du in dem Falle den Wert von
Delphi-Quellcode:
änderst, dann wird der Wert von
AKey
Delphi-Quellcode:
procedure Foo( AKey : TWohnung );
begin AKey := TWohnung.Create; // In AKey steht jetzt der Wert $22222222 end; procedure Bar; var LKey : TWohnung; begin LKey := TWohnung.Create; // <-- In LKey steht jetzt z.B. der Wert $11111111 Foo( LKey ); // LKey hat jetzt immer noch den Wert $11111111 end;
Delphi-Quellcode:
nicht geändert.
LKey
|
AW: Unterschied zwischen (var AFileStream: TFileStream) und (AFileStream: TFileStream
Holen wir mal ein bisschen aus:
Delphi-Quellcode:
Dingens ist also ein Zeiger auf die Instanz, die mit dem Create-Aufruf angelegt wurde.
procedure TfrmSchiessMichTot.MachWas;
var //Instanzvariable Dingens: TDingens; begin //Erzeugen der Instanz und Ablegen in der Variablen (intern ein Zeiger) Dingens := TDingens.Create;
Delphi-Quellcode:
Folgender Code schadet also nicht, da er nur die Kopie betrifft:
procedure MachDingens(ADingens: TDingens);
//ADingens ist hier eine Kopie der ursprünglichen Instanzvariablen, //zeigt aber somit auch auf dieselbe Instanz, daher lässt sich darüber auf //deren Methoden und Eigenschaften zugreifen
Delphi-Quellcode:
procedure MachDingens(ADingens: TDingens);
begin ADingens := TDingens.Create;
Delphi-Quellcode:
Weist man hier nun dem Parameter einen neuen Wert zu, betrifft das auch die Originalvariable, die somit in der aufrufenden Routine nicht mehr erreichbar ist. Bestenfalls bewirkt das lediglich ein Speicherleck, kann aber auch sehr viel schlimmer ausgehen.
procedure MachDingens(var ADingens: TDingens);
//Hier handelt es sich um die Original-Instanzvariable. Überschreibt man die, //hat man auch in der aufrufenden Routine keinen Zugriff mehr auf die //ursprüngliche Instanz |
Alle Zeitangaben in WEZ +1. Es ist jetzt 21:39 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz