Einzelnen Beitrag anzeigen

Benutzerbild von sirius
sirius

Registriert seit: 3. Jan 2007
Ort: Dresden
3.443 Beiträge
 
Delphi 7 Enterprise
 
#17

Re: kleines OOP Beispiel bitte um Anmerk./Verbesserungvorsch

  Alt 15. Okt 2008, 07:56
Die Objekterstellung ist abgeschlossen, wenn du im constrcutor bist.
Der Code zum Erstellen der Instanz fügt der Compiler bei dem Wort "begin" des Constructors ein. Also, wie gesagt, direkt am Anfang.

Edit: Vielleicht mal konkret.
Jede Methode bekommt ja immer mindestens den Parameter "self" übergeben. Damit kannst du ja auf die Felder deiner Klasse zugreifen. Der Constructor bekommt zusätzlich noch einen Wert mitgegeben. Dieser sagt aus, ob der Constructor eine neue Instanz erstellen soll.

Hier mal eine normale Methode
Delphi-Quellcode:
//aus folgendem Code:
procedure TMeineDaten.SetWert1(const Value: Integer);
begin
  FWert1 := Value;
  FBerechnet:=false;
end;

//wird eigentlich:
procedure TMeineDaten.SetWert1(Self:Pointer; const Value: Integer);
begin
  Self.FWert1 := Value;
  Self.FBerechnet:=false;
end;
Und self zeigt einfach auf eine Art Record, in dem alle deiner Felder (Klassenvariablen) enthalten sind. Self ist dann auch das, was in deiner Objektinstanz "MeineDaten" (oder in Post #10: "test") steht. Ist halt einfach nur ein Zeiger auf deinen InstanzRecord. Und jede Instanz hat ihren eigenen Record.

So, und jetzt noch mal zum Constrcutor. Der hat, wie gesagt, neben "self" noch einen versteckten Parameter:
Delphi-Quellcode:
//aus folgendem Code:
Constructor TMeineDaten.Create;
begin
  fBerechnet:=false;
end;

//wird dann:
Constructor TMeineDaten.Create(Self:Pointer; doCreateClass:Boolean);
begin
  if doCreateClass then
  begin
    Self:=_ClassCreate(Self, True); //Ab hier existiert dein Objekt.
    Result:=Self;
  end;

  Self.fBerechnet:=false;


  if DoCreateClass then
    _AfterConstruction(Self);
end;
Was macht eigentlich _ClassCreate (neben Exceptionbehandlung und pipapo). Es reserviert einfach Speicher mittels new, wie bei einem normalen Record, den man dynamisch anlegt auch. Und dann wird die Adresse auf den Speicher zurückgegeben.

So, und jetzt gibt es zwei Aufrufmöglichkeiten des Constructors:
test:=TMeindeDaten.create; Hier wird DoCreateClass auf True gesetzt und anstatt Self wird ein Zeiger auf die TypInformationen von TMeineDaten übergeben (also TMeineDatenClass oder einfach TClass)
Wenn du jetzt den Constructor (irendwann nach der Instanzierung) nochmal so aufrufst (quasi, wie jede andere Methode auch):
test.create; dann ist DoCreateClass=False und an self wird eben der Wert von test übergeben (wie bei jeder anderen Methode auch).
Nebenbei: Wenn jetzt test noch nicht instanziert wäre und du einfach test.create aufrufst (Was ein typischer Delphi-Anfängerfehler ist), wird für self eben nil (oder ein anderer krummer Wert) übergeben und DoCreateClass ist natürlich false. Dann greifst du hier auf den Record nil.fBerechnet zu, was eine Access Violation, meist in der Nähe von Addresse 0 = nil, auslöst.

Allerdings ist es unüblich test.Create direkt aufzurufen. Der Zustand tritt eher ein, wenn man von TMeineDaten eine neue Klasse ableitet und dort, in einem neuen Constructor, dann inherited aufruft. Dann wird der Vorfahr, was TMeineDaten.Create ist, mit DoClassCreate=False aufgerufen.

Ich hoffe ich habe nicht zu sehr verwirrt. Hier ist es auch nochmal schön beschrieben.

Edit2:
Erst die Klasse instanzieren und dann einen weiteren Befehl zur Initialisierung aufrufen ist in anderen Sprachen (die wir hier nicht erwähnen wollen) notwendig. In Delphi kannst du instanzieren und initialisieren in einem Abwasch, eben im constructor, machen.
Dieser Beitrag ist für Jugendliche unter 18 Jahren nicht geeignet.
  Mit Zitat antworten Zitat