Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - Prozedur, Constructor


Grafix - Mi 25.03.09 21:09
Titel: Prozedur, Constructor
Hey,

ich weiß, ich weiß, ihr habt schon 1000 mal erklärt wie OOP funktioniert, und wo man entsprechende Lektüren im Internet finden kann, jedoch kann ich daraus nicht verstehen, was das mit diesem Constructor wirklich auf sich hat, bzw worin der unterschied zwischen procedure, function und constructor besteht. Ich schreibe am Montag mein Abi im InfoLK, meine Stärke liegt jedoch gewiss nicht auf OOP :(
Danke für eure Hilfe!
mfG

Chris


Xentar - Mi 25.03.09 21:13

constructor wird aufgerufen, um eine Instanz einer Klasse zu erzeugen, also normalerweise "Create".
Passend dazu gibts auch den Destructor, standardmäßig "Destroy".


Grafix - Mi 25.03.09 21:17

jep, so stets überall...
aber wie ist das in dem entsprechenden Beispiel?:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
TDatensatz = class
  filmID: string;
  title: string;
  regisseur: string;
  constructor create (f, t, r: string);
end;

constructor TDatensatz.create(f,t,r: string);
begin
  filmID := f;
  titel := t;
  regisseur: r;
end;


was genau bedeutet der constructor in TDatensatz, und wieso schreibe ich beim zweiten CodeSchnippsel constructor statt procedure?!


Yogu - Mi 25.03.09 21:23

In deinem Beispiel macht der Konstruktor wirklich keinen Sinn, denn da fehlt eine wichtige Zeile:


Delphi-Quelltext
 
8:
9:
10:
11:
12:
13:
14:
{ ... }
constructor TDatensatz.create(f,t,r: string);
begin
  inherited Create;
  filmID := f;
  titel := t;
  regisseur: r;
end;

Ein Konstruktor reserviert den nötigen Speicher für das Objekt und initialisiert es. Das macht bereits der Konstruktor der Klasse TObject. Alle abgeleiteten Klassen erweitern ihn. Ein Zeiger auf die neue Instanz wird zurückgegeben, also wäre ein Konstruktor eher mit einer Funktion als einer Prozedur vergleichbar.


user profile iconGrafix hat folgendes geschrieben Zum zitierten Posting springen:
was genau bedeutet der constructor in TDatensatz, und wieso schreibe ich beim zweiten CodeSchnippsel constructor statt procedure?!

Welcher zweite Codeschnipsel? :gruebel:


Grafix - Mi 25.03.09 21:28

Lol, das ist ein Ausschnitt aus eine Abituraufgabe, der zu analysieren ist, ich habe ihn 1:1 übernommen...

inherited bedeutet geerbt oder? wieso Create? (Fragen über Fragen^^)

user profile iconYogu hat folgendes geschrieben Zum zitierten Posting springen:
also wäre ein Konstruktor eher mit einer Funktion als einer Prozedur vergleichbar.


das ist ja meine Frage, woher weiß ich wann ich constructor, procedure oder function verwenden muss?

-> mit dem zweiten Codeschnippsel meinte ich das constructor TDatensatz.create...

schon mal danke für eure Hilfe!!!


Yogu - Mi 25.03.09 21:36

user profile iconGrafix hat folgendes geschrieben Zum zitierten Posting springen:
Lol, das ist ein Ausschnitt aus eine Abituraufgabe, der zu analysieren ist, ich habe ihn 1:1 übernommen...

:rofl: (Sollen die ruhig mal probieren, da kommt AFAIK eine Zugriffsverletzung ;))

user profile iconGrafix hat folgendes geschrieben Zum zitierten Posting springen:
inherited bedeutet geerbt oder? wieso Create? (Fragen über Fragen^^)

Ok, nochmal von vorne.

TObject hat einen Konstruktor namens Create. Dieser initialisiert das Objekt. TDatensatz überschreibt ihn. Überschreiben heißt erst einmal komplett löschen und neu schreiben. Damit der alte Code nicht verloren geht muss er per inherited Methodenname; aufgerufen werden - die Methode heißt in diesem Fall Create.

user profile iconYogu hat folgendes geschrieben Zum zitierten Posting springen:
woher weiß ich wann ich constructor, procedure oder function verwenden muss?

Ganz einfach: Create ist ein Konstruktor, Destroy ein Destruktor und alle anderen sind Prozeduren und Funktionen (den Unterschied kennst du aber, oder?).


JayEff - Mi 25.03.09 21:37

user profile iconYogu hat folgendes geschrieben Zum zitierten Posting springen:

Delphi-Quelltext
 
8:
9:
10:
11:
12:
13:
{ ... }
TDatensatz = class {(kein Vorfahre?)}
  filmID: string;
{...}
constructor TDatensatz.create(f,t,r: string);
begin
  inherited Create;
Von was soll Create denn geerbt werden, wenn die Klasse keinen Vorfahren hat? :nixweiss:


Yogu - Mi 25.03.09 21:38

user profile iconJayEff hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconYogu hat folgendes geschrieben Zum zitierten Posting springen:

Delphi-Quelltext
 
8:
9:
10:
{ ... }
constructor TDatensatz.create(f,t,r: string);
begin
  inherited Create;
Von was soll Create denn geerbt werden, wenn die Klasse keinen Vorfahren hat? :nixweiss:

Alle Klassen sind von TObject abgeleitet - und da steht jede Menge (vielleicht auch magischer) Code im Konstruktor.


JayEff - Mi 25.03.09 21:39

user profile iconYogu hat folgendes geschrieben Zum zitierten Posting springen:

Alle Klassen sind von TObject abgeleitet - und da steht jede Menge (vielleicht auch magischer) Code im Konstruktor.
Hm, das mag sein, damit hab ich mich nie groß beschäftigt. Ist auch irgendwie logisch, dass der Konstruktor ohne die ganze Magie nicht funktioniert :motz:


Grafix - Mi 25.03.09 21:43

constructor bedeutet also nur, dass TDatensatz initialisiert wird und in diesem Constructorbereich können Variablen deklariert werden, oder? Das heißt nach Constructor muss immer entweder Create oder Destroy stehen?

Gibts irgendwo im Netz ein Tutorial, dass OOP Schritt für Schritt an Beispielen LEICHT verständlich erklärt?^^


Yogu - Mi 25.03.09 21:49

user profile iconYogu hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconGrafix hat folgendes geschrieben Zum zitierten Posting springen:
Lol, das ist ein Ausschnitt aus eine Abituraufgabe, der zu analysieren ist, ich habe ihn 1:1 übernommen...

:rofl: (Sollen die ruhig mal probieren, da kommt AFAIK eine Zugriffsverletzung ;))

Ok, ich nehm alles zurück - das klappt tatsächlich (Delphi 2005). :oops:

Wahrscheinlich steckt die Magie einfach im Konstruktor.

Ich hab mal versucht, einen Konstruktor zu basteln, der aus einer Funktion besteht. Erste Möglichkeit:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
type
  TMyObject = class
  public
    MyVar: Integer;

    function MyCreate: TMyObject;
  end;

Problem beim Aufruf: Die Funktion ist nur für initialisierte Objekte gültig, ein TMyObject.MyCreate geht nicht.

Zweiter Versuch:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
type
  TMyObject = class
  public
    MyVar: Integer;

    class function MyCreate: TMyObject;
  end;

Es gibt ein Self und folglich kann auch nichts initialisiert werden.

Fazit: Ein Konstruktor ist eine class function, die aber eine Instanz von sich selbst erzeugt und darauf zugreifen kann.

user profile iconGrafix hat folgendes geschrieben Zum zitierten Posting springen:
constructor bedeutet also nur, dass TDatensatz initialisiert wird und in diesem Constructorbereich können Variablen deklariert werden, oder?

Genau. :zustimm:

user profile iconGrafix hat folgendes geschrieben Zum zitierten Posting springen:
Das heißt nach Constructor muss immer entweder Create oder Destroy stehen?

Create ja, Destroy nein: Dafür gibts destructor.

user profile iconGrafix hat folgendes geschrieben Zum zitierten Posting springen:
Gibts irgendwo im Netz ein Tutorial, dass OOP Schritt für Schritt an Beispielen LEICHT verständlich erklärt?^^

Suche bei Google DELPHI OOP TUTORIAL ;)
Erstes Ergebnis: Delphi-Tutorials - OOP in Delphi [http://www.delphitutorials.de/oop-in-delphi.html].


Grafix - Mi 25.03.09 21:52

hey, unterstell mir nicht ich hätte nicht auch in Google gesucht, meinem Freund und Helfer, ich war sogar schon auf der Seite, habe aber nur den riesen Codeschnippsel gesehn und bin schnell wieder geflohen^^
Danke für die Hilfe, werde mich mal am Tutorial versuchen.
Super Forum!


Yogu - Mi 25.03.09 21:55

user profile iconGrafix hat folgendes geschrieben Zum zitierten Posting springen:
ich war sogar schon auf der Seite, habe aber nur den riesen Codeschnippsel gesehn und bin schnell wieder geflohen^^

Das hätte ich auch fast, bis ich bemerkt habe, dass Google auf Seite 9 verlinkt. Versuch dich mal am Anfang des Tutorials ;)


Grafix - Mi 25.03.09 22:15

kleine Zwischenfrage, was bedeutet FValue: Currency?


Marc. - Mi 25.03.09 22:19

user profile iconGrafix hat folgendes geschrieben Zum zitierten Posting springen:
kleine Zwischenfrage, was bedeutet FValue: Currency?

Deklariert eine Feld-Variable vom Typ Currency:
DOH hat folgendes geschrieben:
Der Typ Currency ist ein Festkomma-Datentyp, der Rundungsfehler in finanzmathematischen Berechnungen minimiert. In Win32 wird er als skalierter 64-Bit-Integer gespeichert, bei dem die vier niedrigstwertigen Stellen implizit vier Nachkommastellen repräsentieren. Bei einer Kombination mit anderen reellen Typen in Zuweisungen und Ausdrücken werden Currency-Werte automatisch mit 10000 multipliziert.

Mehr dazu findest Du in Deiner Delphi-Online-Hilfe. (Mauszeiger über das Codewort halten und F1 drücken)


der organist - Mi 25.03.09 22:20

user profile iconGrafix hat folgendes geschrieben Zum zitierten Posting springen:

das ist ja meine Frage, woher weiß ich wann ich constructor, procedure oder function verwenden muss?


Naja, bevor du ein Objekt benutzen kannst, muss du es am Anfang erzeugen. Mit einem constructor. Danach kannst du ganz normal Prozeduren benutzen. Am Ende musst du noch noch den Speicherplatz freigeben, so dass keine "Speicherlöcher" (unbenutzbarer Speicher" entstehen.

Ob nun ein Constructor mehr Funktion als Prozedur ist, lass ich mal außen vor, dann kann ich einfach keine Senf zu geben, aber im Gegensatz zu einer normalen prozedur wird zusätzlich das Objekt erzeugt, selbiges beim destructor.

Deine Zwischenfrage kann ich leider nicht beantworten.

EDIT: Da war wohl jemand schneller

EDIT: ich füg mal noch etwas mehr Erklärung hinzu...

Ah und dann fehlt noch, was eine Funktion ist und der Unterschied von ner Proc. und Func.:

in einer Prozedur (so mach ich das zumindest) kannst du Werte verändern, auch Ereignisse wie Buttonklicks reagieren etc. Eine Funktion hingegen, naja, was ist eine mathematische Funktion? Du gibst einen x-Wert und bekommst nen y-Wert zurück. In Delphi gibst du der Funktion ein Argument und bekommst danach einen Wert zurück. Das kann sein wie in einer (hier selbstdefinierten Funktion (bitte bei Fehlern drauf hinweisen, ich probier das jetzt ncih in Delphi aus):


Delphi-Quelltext
1:
2:
3:
4:
function Multiply (AFactor1, AFactor2, AFactor3:Extended):Extended;
begin
  Multiply:=AFactor1*AFactor2*AFactor3;
end;


Wenn du die Funktion aufrufst, wie im folgenden Beispiel, erhälst du das Produkt:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
procedure myButton.Click(Sender:TObject); //da fehlt mit Sicherheit was, ist aber nich so wichtig, wir haben einen                              
                                          //Button sowie drei Editfelder und ein Label
begin
  Label1.Caption:=FloatToStr(Multiply(StrToFloat(Edit1.Text),
                                      StrToFloat(Edit2.Text),
                                      StrToFloat(Edit3.Text)));
end;


danach wird dir im Label das Multiplikationsergebnis angezeigt. In diesem beispiel ist es eigentlich total simpel, die ganze Sache ohne Funktion zu schreiben, aber es gibt ein paar Sachen, die (a) wesentlich schwieriger sind und [b] teilweise schon von Borland (?) vorgefertigt sind:


Delphi-Quelltext
1:
2:
3:
FormatDateTime({String für die Schreibform des Datums/der Zeit},{Zeitpunkt, von dem die Zeit angezeigt wird});

DayOfTheYear({Datum, von dem die Tagesnummer angezeigt werden soll});


Beispiel für einen Constructor, meist ist es nützlich einen zu schreiben (weil man dort z.B: Startwerte zuweisen kann...ohne nachher auf die Felder (Variablen, Arrays , wie auch immer ) direkt zuzugreifen, so dass man diese privat deklarieren kann):


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
constructor TPlayer.Create(AName:String;APoints:Integer);
begin
  SetLength(Islands,0);        //dynamisches Array, kann nicht schaden, es auf Länge null zu setzen
  Points:=APoints;             //Punkteanzahl ist privat deklariert
  Name:=AName;                 //genauso wie der Name
end;


Hoffe es ist etwas verständlicher geoworden. Diejenigen, die noch erfahrener sind, mögen mich korrigieren, wenn nötig.


Grafix - Mi 25.03.09 23:17

danke für eure schnellen und ausführlichen antworten! habt mir wirklich geholfen, versuche mich dann mal weiter am Tutorial


jaenicke - Mi 25.03.09 23:27

user profile iconYogu hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconJayEff hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconYogu hat folgendes geschrieben Zum zitierten Posting springen:

Delphi-Quelltext
 
8:
9:
10:
{ ... }
constructor TDatensatz.create(f,t,r: string);
begin
  inherited Create;
Von was soll Create denn geerbt werden, wenn die Klasse keinen Vorfahren hat? :nixweiss:

Alle Klassen sind von TObject abgeleitet - und da steht jede Menge (vielleicht auch magischer) Code im Konstruktor.
Du hast es ja auch selbst schon festgestellt, aber ich wollte dir den magischen Code nicht vorenthalten: :mrgreen:

Delphi-Quelltext
1:
2:
3:
constructor TObject.Create;
begin
end;
Da der Konstruktor nicht als virtuell gekennzeichnet ist, kannst du den auch nicht überschreiben sondern musst ihn normal neu schreiben.

Trotzdem ist das inherited sinnvoll, z.B. wenn man mal die Klasse ändert, von der abgeleitet wurde. ;-)


Yogu - Do 26.03.09 16:51

user profile iconder organist hat folgendes geschrieben Zum zitierten Posting springen:
Ah und dann fehlt noch, was eine Funktion ist und der Unterschied von ner Proc. und Func.:

Wetten, ich schaffe es etwas kürzer zu erklären?

Eine Funktion kann Werte zurückliefern. :mrgreen:

user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconYogu hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconJayEff hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconYogu hat folgendes geschrieben Zum zitierten Posting springen:

Delphi-Quelltext
 
8:
9:
10:
{ ... }
constructor TDatensatz.create(f,t,r: string);
begin
  inherited Create;
Von was soll Create denn geerbt werden, wenn die Klasse keinen Vorfahren hat? :nixweiss:

Alle Klassen sind von TObject abgeleitet - und da steht jede Menge (vielleicht auch magischer) Code im Konstruktor.
Du hast es ja auch selbst schon festgestellt, aber ich wollte dir den magischen Code nicht vorenthalten: :mrgreen:

Delphi-Quelltext
1:
2:
3:
constructor TObject.Create;
begin
end;

Gut, mit magischem Code meinte ich ja auch kein Delphi-Quelltext, sondern Compiler Magic. Die sieht man recht schlecht in der Quelldateien und befindet sich schon im Schlüsselwort constructor ;)

user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Da der Konstruktor nicht als virtuell gekennzeichnet ist, kannst du den auch nicht überschreiben sondern musst ihn normal neu schreiben.

Was ja irgendwie auf das gleiche rauskommt, oder? Außer natürlich dem fehlenden override.

user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Trotzdem ist das inherited sinnvoll, z.B. wenn man mal die Klasse ändert, von der abgeleitet wurde. ;-)

Deshalb ist es auch gut, sich ein inherited Create; anzugewöhnen - wenn man später die Elternklasse ändert, denkt man unter Umständen nicht daran, den Konstruktor anzupassen. :idea:


Zorro - Do 26.03.09 18:15

user profile iconder organist hat folgendes geschrieben Zum zitierten Posting springen:

Ob nun ein Constructor mehr Funktion als Prozedur ist, lass ich mal außen vor, dann kann ich einfach keine Senf zu geben, ...


Ist (wenn man das denn überhaupt einstufen will) als Funktion einzustufen, da der Constructor das soeben erzeugte Objekt zurückgibt:

MyObj := TMyOb.Create(nil);

Greetz
Zorro


jaenicke - Do 26.03.09 18:17

Genau gesagt würde ich es als spezielle class function bezeichnen. ;-)


Yogu - Do 26.03.09 19:56

user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Genau gesagt würde ich es als spezielle class function bezeichnen. ;-)


user profile iconYogu hat folgendes geschrieben Zum zitierten Posting springen:
Ein Konstruktor ist eine class function, die aber eine Instanz von sich selbst erzeugt und darauf zugreifen kann.

Alles alter Kaffee :mrgreen:


delfiphan - Do 26.03.09 20:24

user profile iconder organist hat folgendes geschrieben Zum zitierten Posting springen:
... aber im Gegensatz zu einer normalen prozedur wird zusätzlich das Objekt erzeugt, selbiges beim destructor.

Jein; wird der Konstruktor über eine Objektreferenz aufgerufen bzw. über Self, wird kein neues Objekt mehr erzeugt. Es gibt eine Fallunterscheidung. Nicht immer "kreiert" der Konstruktor was.

Im Übrigen ruft der Konstruktur auch NewInstance und AfterConstruction und besitzt einen Exception-Handler, der dafür sorgt, dass im Fehlerfall der Destruktor aufgerufen wird.