Entwickler-Ecke
Delphi Language (Object-Pascal) / CLX - Erstellung von Instanzen
flowstar - Fr 19.03.04 18:08
Titel: Erstellung von Instanzen
Ich hab mal ne Frage zur Delphi Syntax:
Warum heisst es bei der Erstellung von Instanzen
Delphi-Quelltext
1:
| Test := TKlasse.Create |
und nicht
Hat das nen sinn?
Christian S. - Fr 19.03.04 18:09
Hallo!
Bitte ändere den Titel des Topics da er wenig über das eigentlich Thema verrät. Hier der entsprechende Absatz aus den Delphi-Forum.de Richtlinien:
| Richtlinien hat folgendes geschrieben: |
1.1 Beiträge
Bitte formuliere den Betreff Deiner Beiträge so, dass andere Mitglieder anhand dieser bereits das eigentliche Thema festmachen können. Beiträge wie etwa "Eine Anfängerfrage" oder "Weiß jemand, wie das geht?" lassen den Leser im Unklaren darüber, was das Thema der Diskussion ist.[...]
|
Einfach oben bei deinem ersten Beitrag auf "Edit" klicken und den Titel ändern. Dank Dir!
Gruß Peter Lustig
MaxiTB - Fr 19.03.04 18:12
Erstens mal ists keine blöde Frage sondern ein blöder Titel - bei sowas wundere dich nicht, wenn du in Zukunft keine Ahnung kriegst. Stehst sich schon auf der watchlist von einigen.
Zweitens ist Create ein constructor - der reserviert Speicher und gibt eine Referenz auf diese Objekt-Instanz zurück.
Wenn du xxx.Create schreibst, dann verwendest du bereits eine Instanz - die gibts aber noch nicht, weil Delphi keine statische Erzeugung von Objekten unterstützt. Somit hats du zu beginn nur eine ungültige Referenz-Variable, welcher du mit Create eine gültige zuweist.
//Edit: Die Mods sind aber heute wieder flott. :shock:
flowstar - Fr 19.03.04 18:23
Besser so?
Ihr seid heute aber mal wieder gut gelaunt...
bms - Fr 19.03.04 18:36
Eigentlich ist es unlogisch. Denn, einerseits scheibe ich
Delphi-Quelltext
1: 2:
| var Bitmap: TBitmap; |
und dann muß ich noch mal
Delphi-Quelltext
1:
| Bitmap := TBitmap.Create; |
schreiben.
Was erwartet der Compiler wenn ich eine Bitmap Variable vom Typ TBitmap deklariere? Erwartet der, daß ich später ein Icon Objekt erstelle? Eigentlich ist es doppelte Pflege. Entweder einfach nur einen Zeiger deklarieren und erst später den Typ bei Create festlegen, oder beim deklarieren den Typ zuweisen und später einfach nur noch Create. Eine ander Möglichkeit hat man sowieso nicht, oder?
Oder kann einer genau sagen wieso es wichtig ist zwei mal drauf hinzuweisen was für Typ es ist?
Christian S. - Fr 19.03.04 18:38
| Zitat: |
| //Edit: Die Mods sind aber heute wieder flott. |
Möchtest Du damit dezent anmerken, dass wir manchmal nicht flott sind? ;-) :lol:
//edit:
Du kannst Deine Variable ja auch als Referenz auf ein bereits erzeugtes Objekt benutzen und musst dann gar kein neues Objekt erzeugen
MaxiTB - Fr 19.03.04 18:40
::bms
Du mußt den constructor sehen wie eine statische Methode - ähm - tschuldigung, Klassenmehtode heißts auf Delphisch.
Das heißt, bei Klassenmethoden gibts du ja auch die Klasse an Punkt Methode.
Mit der Variablendeklaration erzeugst du ja nur eine Referenz auf ein Objekt - und die weißt du später zu.
::peter
Hätte ich schreiben sollen zuuu flott ? *g*
Ich denke mal, daß besprechen wir mal lieber bei einem Bier ... ähm - aber dann bitte keine C/Delphi Performance Diskusssion - davon hatte ich heute schon genug ;-) .
Delete - Fr 19.03.04 19:47
| bms hat folgendes geschrieben: |
| Was erwartet der Compiler wenn ich eine Bitmap Variable vom Typ TBitmap deklariere? Erwartet der, daß ich später ein Icon Objekt erstelle? |
Du übersiehst, dass jedes Objekt, das du erstellst, nicht nur einfach angelegter Speicher ist. Mit jedem Objekt verbunden sind Methoden, die vielleicht nur unter ganz bestimmten Bedingungen ausgeführt werden können.
Angefangen schon beim Konstruktor: Vielleicht braucht der eine bestimmte Variable oder ein anderes Objekt, wie einen Parent. Oder eine Prozedur muss vorher eine benötigte dll-Datei laden.
Da Delphi natürlich nicht wissen kann, wann es sicher ist, die Komponente zu erstellen, musst du es selber in deinem Code machen.
Da es in Delphi jedoch üblich ist, alle Variablen und Objekte, die du im Code nennen willst, vorher zu deklarieren, musst du vorher schon die Variable anlegen, in die dein Konstruktor dann die Komponente erstellen kann.
bms - Fr 19.03.04 19:50
| MaxiTB hat folgendes geschrieben: |
Du mußt den constructor sehen wie eine statische Methode - ähm - tschuldigung, Klassenmehtode heißts auf Delphisch.
Das heißt, bei Klassenmethoden gibts du ja auch die Klasse an Punkt Methode.
Mit der Variablendeklaration erzeugst du ja nur eine Referenz auf ein Objekt - und die weißt du später zu. |
Das Prinzip ist mir klar, nur erscheint es mir nicht logisch, daß es zwei mal sein muß. Allerdings kann ich mich damit abfinden, daß es bei Pascal so sein muß da es nicht anders ging (gemeint sind die Pascalkonventionen). Wenn ich zum Beispiel den Code-Vervollständiger nutze und hinter einer Bitmapvariable, d.h. hinter "Bitmap :=", STRG + LEERTASTE drücke, dann wird der korrekte Klassentyp angeboten (vorausgesetzt ich hab Bitmap als TBitamp deklariert). Delphi weiß also was kommen muß, verlangt aber dennoch das man TBitamp noch mal vor Create plaziert. Ich kann mir vorstellen, daß es auch anders und einfacher funktionieren könnte. Aber ich hab keine Probleme damit. Wenn aber eines sagen könnte wieso es so sein muß, dann wäere es nicht schlecht.
Delete - Fr 19.03.04 19:59
Hallo???
Hast du meinen Post gelesen?
Na ja... schätze war gleichzeitig.
bms - Fr 19.03.04 21:08
Eigentlich ist es egal und nicht so wichtig. Ich hab das Prinzip schon verstanden.
Es geht nicht drum, daß es gemacht wird. Die Frage ist also nicht warum man an erst an einer Stelle mit Create ein Objekt erstellt. Das sind nicht die Fragen. Die Frage ist wieso nicht einfach ein Create. Wieso haben die Entwickler von Delphi es so vorgesehen und nicht anders. Wieso nicht einfach ein
Delphi-Quelltext
1: 2: 3: 4:
| var Bitmap: TBitmap; begin Bitmap.Create; |
oder mindesten
Delphi-Quelltext
1:
| Bitmap := Object.Create; |
Was kann es anderes sein als TBitmap. Eigentlich dürfte es kein Problem sein. Der Compiler weiß, daß es NUR TBitmap sein kann, da Bitmap vom Typ TBitmap ist.
Wenn ich es so mache.
Delphi-Quelltext
1: 2: 3: 4:
| var Bitmap: TBitmap; begin Bitmap := TBitmap.Create; |
dann schreibe ich zwei mal TBitmap, also ein mal doppelpflege.
Aber ich gehe davon aus, daß Delphi (oder genauer Pascal) nicht als Objektsprache entwickelt wurde. Deshalb hat man sich etwas zusammengeschustert was man noch als Pascal verkaufen konnte.
UC-Chewie - Fr 19.03.04 21:19
| bms hat folgendes geschrieben: |
| Was kann es anderes sein als TBitmap. Eigentlich dürfte es kein Problem sein. Der Compiler weiß, daß es NUR TBitmap sein kann, da Bitmap vom Typ TBitmap ist. |
Und genau da liegt dein Irrtum. Du kannst durchaus in dem von dir genannten Fall eine Instanz vom einer von TBitmap abgeleiteten Klasse erstellen. Das Stichwort dazu lautet
POLYMORPHIE bzw.
POLYMORPHISMUS, zu deutsch "Vielgestaltigkeit".
Delete - Fr 19.03.04 21:29
Du kannst aber TBitmap.Create auch aufrufen, ohne das Ergebnis in eine Variable zu schreiben (das ginge sonst nicht).
Sinnvoll z.B. für Klassen, die sich sebst irgendwo registrieren.
Auch hat man so die Möglichkeit, für eine bestehende Instanz noch einmal Create ausführen zu lassen, ohne eine neue Instanz zu erstellen.
Nebenbei finde ich die Syntak eigentlich so ganz logisch und verstehe überhaupt nicht, weshalb du dich so aufregst...
Man ruft ja eine Funktion auf, nämlich den Konstruktor, und weist der Variablen auf der linken Seite deren Ergebnis zu (die neu geschaffene Instanz).
Vielleicht steht links bis jetzt nil, oder eine alte Referenz auf ein längst freigegebenes Objekt. Aber auf jeden fall steht da nichts nichts, mit dem ich etwas ausführen möchte, sondern etwas, von dem ich möchte, dass es überschrieben wird.
Für mich total logisch!!
bms - Fr 19.03.04 22:23
Ok, lassen wir es. Anscheinend wird die Frage immer wieder mißverstanden. Ist auch nicht schlimm. Nur geht es mir die ganze Zeit um was anderes. Aber irgendwie kann ich nicht verständlich machen was ich meine. Ist egal.
Delete - Sa 20.03.04 08:38
Was denn?
Du hast gefragt, warum man erst bei der Deklaration " :
TBitmap" schreibt und dann beim Aufruf des Konstruktors nochmal " :=
TBitmap.Create ".
Genau das haben dir jetzt einige Leute beantwortet. Was daran jetzt noch falschverstanden werden könnte, ist mir nicht klar.
Ich stimme jetzt vielleicht so weit überein, dass man den Compiler auch hätte veranlassen können bei...
Delphi-Quelltext
1: 2: 3:
| Var Test:TBitmap; ... Test:=Create; |
...automatisch ein TBitmap zu erstellen. Trotzdem müsste dann aus genannten Gründen aber wenigstens die Möglichkeit bleiben, ein anderes Create aufzurufen.
bms - Sa 20.03.04 09:28
Siehst du, über mehr wollte ich auch nicht diskutieren. Mir ist bewußt, daß es mehrere Konstruktoren geben kann und das einige Klassen auch mehrere Konstruktoren haben. Mir ist bewußt, daß es Polymorphie gibt und wozu sie dient. Mir ist auch bewußt, daß ich ein Objekt erstellen kann ohne eine Variable. Mir ist auch der Unterschied zwischen einer Variable, einer Klasse und einem Objekt bewußt. All das weiß ich und über das wollte ich auch nicht reden. Aber ich weiß von vielen Anfängern, durch vierschiedenen Forumsfragen, was viele gerade am Anfang für verwirend halten. Warum gerade so und nicht anders. Würde ich eine Objektorientierte Programmiersprache entwickeln, dann hätte ich einige anders gemacht. Ich hab mir mal Gedanken gemacht über Delphi und wie Delphi mit Objekten umgeht. Und meiner Meinung nach ist das nicht optimal. Es sieht irgendwie zusammengeschustert aus. Daruber wollte ich diskutieren, nur darüber.
Motzi - Sa 20.03.04 14:05
Es gibt einen Unterschied zwischen zwischen den beiden Aufrufen.
Delphi-Quelltext
1: 2: 3: 4: 5:
| var aBitmap: TBitmap;
aBitmap := TBitmap.Create; aBitmap.Create; |
Im ersten Fall wird Create als Constructor aufgerufen, also quasi als Klassenmethode die ohne ein Objekt auskommt. Stattdessen wird eben ein neues Objekt der angegebenen Klasse erzeugt und die Referenz darauf zurückgegeben.
Im zweiten Fall wird Create als Methode aufgerufen, und zwar nicht mehr als Klassenmethode, sondern als Methode das Objekts (in diesem Fall eben aBitmap). Es wird kein neues Objekt erzeugt, sondern es wird nur ganz normal der Code der Create-Methode abgearbeitet und in diesen Fall eben auf das Objekt bezogen über das die Methode aufgerufen wurde.
Das ist auch wichtig, dass es diese Unterscheidung gibt! Wenn du dich ein bisschen in OOP auskennst weißt du zB, dass man einen Konstruktor überschreiben kann und über inherited den geerbten Konstruktor aufrufen kann. zB:
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:
| type TMyFirstClass = class(TObject): private F: Integer; public constructor Create(x: Integer); virtual; end;
TMySecondClass = class(TMyFirstClass ) public constructor Create(x: Integer); override; end;
constructor TMyFirstClass.Create(x: Integer); begin inherited Create; F := x; end;
constructor TMySecondClass.Create(x: Integer); begin inherited Create(x); F := F + x; end; |
Stell dir nun vor es wird mit folgendem Code eine Instanz von TMySecondClass erstellt:
Delphi-Quelltext
1: 2: 3: 4:
| var aObject: TMySecondClass;
aObject := TMySecconfClass.Create(5); |
Was passiert da nun wirklich? Zuerst wird der Konstruktor von TMySecondClass aufgerufen und zwar
als Konstruktor und nicht als Methode, es wird also eine Instanz von TMySecondClass erstellt und dann der Code des Konstruktors aufgerufen. Aber was passiert da in dieser Zeile?
Hier wird der geerbte Konstruktor von TMyFirstClass aufgerufen, aber eben nicht als Konstruktor der ein neues Objekt erzeugt, sondern im Prinzip als normale Methode die sich auf das Objekt bezieht das der Konstruktor von TMySecondClass erstellt hat. Das muss ja auch so sein, da der geerbte Konstruktor dafür verantwortlich ist die geerbten Eigenschaften und Felder mit brauchbaren Werten zu füllen!
Ich hoffe das hilft dir ein bisschen das ganze zu verstehen, auch wenn das Beispiel vielleicht nicht ganz so gut zeigt was ich dir zu erklären versuche. Noch deutlicher wird das ganze wenn du mehrere verschiedene Klassen hast und jede mit mehreren verschiedenen Konstruktoren die sich untereinander selbst aufrufen und zwar sowohl von der eigenen Klasse als auch von den Basisklassen (wie ich es gerade in einem meiner Projekte habe). Aber so ein Beispiel hier anzuführen sprengt etwas den Rahmen und wäre auch zu kompliziert zum erklären...
Delete - Sa 20.03.04 15:39
Hm... das hatten ja schon mehrere oben erklärt, wenn auch keiner so ausführlich.
Also wenn ich flowstar jetzt richtig verstanden habe, dann ging es ihm auch gar nicht darum.
Er wollte nur wissen, warum es keine Kompilervereinfachung gibt, die es einem erspart, zwei mal TBitmap schreiben zu müssen.
Jetzt wo's hier aber alles schon mal so ausführlich steht, sollte man es vielleicht als gekürzte Fassung in die FAQ übernehmen.
Am besten gleich dazu beantworten, warum man mit TBitmap:=TBitmap keine Instanzen kopiert und warum und wann man Free aufrufen sollte.
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!