Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Object via Typecast erzeugen (https://www.delphipraxis.net/139562-object-via-typecast-erzeugen.html)

Zerolith 31. Aug 2009 19:19


Object via Typecast erzeugen
 
@Mods - Bitte korrigiert den Titel falls euch was besseres einfällt:

Ich versuche folgendes:

Delphi-Quellcode:

type
  TxObject = class
  public
    constructor Create;
  end;

  TxUser = class(TxObject)
  public
    constructor Create;
  end;

  TxObjectClass = class of TxObject;

[...]

var
  o: TxObject;
  fOwnerClass: TxObjectClass;
begin
  fOwnerClass := TxUser;
  // HIER
  o := TxObject(fOwnerClass.Create);
  //...
  [..]
end;
sieht vielleicht eigenartig aus - aber nur weils komplett zusammengekürzt ist. Liegt deutlich mehr dahinter :-)

Der Code oben funktioniert zwar, allerdings wird der Constructor von TxUser NIE aufgerufen. Warum? Bin mir leider auch nicht ganz sicher nach was ich hier / Google suchen hätte sollen.

Danke, Daniel

Apollonius 31. Aug 2009 19:20

Re: Object via Typecast erzeugen
 
Mach den Konstruktor von TxObjekt virtuell und gib dann in TxUser die Direktive override an.

Zerolith 31. Aug 2009 19:25

Re: Object via Typecast erzeugen
 
Ach natürlich... Danke dir recht herzlich.

macht, wenn folgendes der fall ist, auch keine Probleme oder?


Delphi-Quellcode:
TxDBObject = class
public
  constructor Create;
end;

TxObject = class(TxDBObject)
public
  constructor Create; virtual;
end;

TxUser = class
public
  constructor Create;
end;
Hier werden dann auch der Constructor von TxDBObject + TxObject aufgerufen, oder?

Apollonius 31. Aug 2009 19:31

Re: Object via Typecast erzeugen
 
Du musst bedenken, was der Compiler macht. Wenn du fOwnerClass.Create schreibst, sieht der Compiler, dass fOwnerClass "mindestens" TxObject ist; das Create bezeichnet also den Konstruktor von TxObject. Nur wenn dieser Konstruktor virtuell ist, wird ein virtueller Dispatch angestoßen; ansonsten wird nur der Konstruktor von TxObject aufgerufen. Wenn du erst in einer abgeleiteten Klasse den Konstruktor virtuell machst, hilft dir das nichts mehr.

Um zu deiner Frage zurückzukommen: Wenn deine Klassenreferenz den Typ class of TxDBObject hat, wird nur TxDBObject.Create aufgerufen; wenn es sich jedoch um class of TxObject handelt, wird virtuell dispatcht. Ob ein geerbter Konstruktor aufgerufen wird, richtet sich nach dem Vorkommen der inherited-Klausel.

Zerolith 31. Aug 2009 22:47

Re: Object via Typecast erzeugen
 
Nochmal danke für die ausführliche Erklärung.
Geholfen hats schon mal aber bin mir nicht sicher ob ich dich verstanden hab:

TxUser >Nachfahre von> TxObject > Nachfahre von > TxdbObject

Wenn TxObject.Constructor = virtuell =>

- TxUser MUSS einen überschriebenen Constructor (mit inherited) haben
- TxObjects' Constructor WIRD aufgerufen.
- TxdbObject Constructor WIRD NICHT aufgerufen?


Wenn ich jetzt STATT(!) bei TxObject den Constructor bei TxdbObject virtuell mache:

- Wird der Constructor von TxObject AUCH beim Erzeugen von einem TxUser aufgerufen, oder nur der von TxdbObject und TxUser.

- Sollte ich dann beide Constructor (TxObject + TxdbObject) virtuell machen?

Danke!

Stevie 1. Sep 2009 06:47

Re: Object via Typecast erzeugen
 
Beim Überschreiben von Methoden solltest du auch beachten, sie mit override zu deklarieren - ansonsten wird dir sowieso eine Warning beim Kompilieren ausgegeben, dass sie die Methode der Vorgängerklasse verdecken.

Beispiel:
Delphi-Quellcode:
  TxDBObject = class
public
  constructor Create;
end;

TxObject = class(TxDBObject)
public
  constructor Create; virtual;
  procedure Foo; virtual;
end;

TxUser = class(TxObject)
public
  constructor Create;
  procedure Foo;
end;
Wenn du eine Instanz von TxUser erstellst und Foo aufrufst, wird diese korrekt von der Klasse TxUser aufgerufen. Solltest du aber diese Instanz in einer Variable vom Typ TxObject speichern und dann Foo aufrufen, würde im obigen Beispiel die Methode von der Klasse TxObject aufgerufen und nicht die deiner tatsächlichen instanzierten Klasse. Dies würde nur geschehen, wenn du TxUser.Foo mit override kennzeichnest.

Zitat:

Zitat von Zerolith
Wenn ich jetzt STATT(!) bei TxObject den Constructor bei TxdbObject virtuell mache:

- Wird der Constructor von TxObject AUCH beim Erzeugen von einem TxUser aufgerufen, oder nur der von TxdbObject und TxUser.

Nur, wenn sowohl der Konstruktor von TxObject und TxUser einen inherited Aufruf haben - und auch hier nicht das override bei den beiden Konstruktoren vergessen.

Zitat:

Zitat von Zerolith
- Sollte ich dann beide Constructor (TxObject + TxdbObject) virtuell machen?

Nein, auch in diesem Fall würdest du beim Kompilieren eine Warnung bekommen, dass der Konstruktor von TxObject den von TxDBObject verdeckt.

Apollonius 1. Sep 2009 16:08

Re: Object via Typecast erzeugen
 
Zitat:

Zitat von Zerolith
Wenn TxObject.Constructor = virtuell =>

- TxUser MUSS einen überschriebenen Constructor (mit inherited) haben
- TxObjects' Constructor WIRD aufgerufen.
- TxdbObject Constructor WIRD NICHT aufgerufen?

Du denkst viel zu kompliziert. Der Compiler ruft per se nie geerbte Konstruktoren auf. Die inherited-Klausel bewirkt das, es muss also explizit angegeben werden. Wenn du in TxObject wieder inherited aufrufst, wird TxdbObject.Create aufgerufen.
Des Weiteren musst du virtuelle Methoden oder Konstruktoren nicht überschreiben. Dies wäre lediglich der Fall bei abstrakten Methoden. Wenn kein expliziter Override angegeben wird, nimmt der Compiler einfach den der Elternklasse (d.h. hier TxObject).


Alle Zeitangaben in WEZ +1. Es ist jetzt 21:44 Uhr.

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