Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi Verwirrung mit override/overload bei Constructoren (https://www.delphipraxis.net/93929-verwirrung-mit-override-overload-bei-constructoren.html)

hsg 13. Jun 2007 13:42


Verwirrung mit override/overload bei Constructoren
 
Es ist zwar kein richtiges Problem (es läuft zwar) aber trotzdem ich bin bei folgendem Konstrukt nicht mehr wirklich sicher, was da passiert:
Delphi-Quellcode:
interface
type
TTextEditor= class(TMyForm)
  public
   constructor Create(AOwner : TComponent); overload; override; // <----- ES GEHT UM DIESE ZEILE
   constructor Create(AOwner : TComponent; lNEm : Boolean); reintroduce; overload;
end;

implementation
//----------------------------------------------------------------------------------------------------------------------
// Klasse erzeugen - Default konstruktor
//----------------------------------------------------------------------------------------------------------------------
constructor TTextEditor.Create(AOwner : TComponent);
begin
  inherited Create(AOwner);
  lNotEmpty := False;
end;

//----------------------------------------------------------------------------------------------------------------------
// Klasse erzeugen - Konstruktor mit Parameter
//----------------------------------------------------------------------------------------------------------------------
constructor TTextEditor.Create(AOwner : TComponent; lNEm : Boolean);
begin
  inherited Create(AOwner);  // <-- Welcher Konstruktor wird hier warum aufgerufen
  lNotEmpty   := lNEm;
  ActionCancel.Enabled := not lNotEmpty;
end;
In der obigen Form kompiliert Delphi ohne zu meckern.

Bei folgenden Varianten kommen entweder Warnungen (nicht schön, will ich weg haben) oder gar Fehler:

Variante 1:
Delphi-Quellcode:
   constructor Create(AOwner : TComponent); override; overload; // <----- ES GEHT UM DIESE ZEILE
   constructor Create(AOwner : TComponent; lNEm : Boolean); reintroduce; overload;
Fehler: Feldbezeichner nicht erlaubt nach Methoden oder Eigenschaften

Variante 2:
Delphi-Quellcode:
   constructor Create(AOwner : TComponent); overload; // <----- ES GEHT UM DIESE ZEILE
   constructor Create(AOwner : TComponent; lNEm : Boolean); reintroduce; overload;
Warnung: W1010 Methode 'Create' verbirgt virtuelle Methode vom Basistyp 'TFormPPS'

Wer klärt mich auf????

SirThornberry 13. Jun 2007 13:47

Re: Verwirrung mit override/overload bei Constructoren
 
variante1 geht nicht weil du overload und override in der falschen Reihenfolge hast.
Und bei variante2 sagt doch die Fehlermeldung aus was nicht stimmt - deine Create-methode verbirgt eben die die Create-Methode von der klasse wovon du ableitest.

Robert Marquardt 13. Jun 2007 14:05

Re: Verwirrung mit override/overload bei Constructoren
 
Brauchst du wirklich zwei Konstuktoren? Geht es nicht vielleicht nur mit dem zweiten und einem Parameter mit Defaultwert?

Es ist ganz klar was bei "inherited Create(AOwner)" aufgerufen wird. Es wird der Konstruktor von TMyForm aufgerufen. Falls Du dort nicht ebenfalls an den Konstruktoren spielst, hat diese Klasse nur einen Konstruktor. Selbst wenn es mehrere Konstruktoren gibt, sichert Delphi ab das es immer eindeutig bleibt. es gibt Fehlermeldungen falls die Deklaration der overloaded Konstruktoren/Methoden nicht eindeutig ist.

SirThornberry 13. Jun 2007 14:08

Re: Verwirrung mit override/overload bei Constructoren
 
überschreiben des alten constructors muss sein damit die ide weiterhin den TComponent-Nachfahren erzeugen kann.
Allerdings würde ich das dann auch etwas anders machen. Und zwar im überschriebenen Constructor einfach den neuen Constructor aufrufen
Delphi-Quellcode:
constructor TTextEditor.Create(AOwner : TComponent);
begin
  Create(AOwner, StandardwertFuerlNEm);
end;

//---------------------------------------------------------------------------------------------------------------------- 
// Klasse erzeugen - Konstruktor mit Parameter
//---------------------------------------------------------------------------------------------------------------------- 
constructor TTextEditor.Create(AOwner : TComponent; lNEm : Boolean);
begin
  inherited Create(AOwner);  // <-- Welcher Konstruktor wird hier warum aufgerufen
  lNotEmpty  := lNEm;
  ActionCancel.Enabled := not lNotEmpty;
end;

hsg 13. Jun 2007 14:23

Re: Verwirrung mit override/overload bei Constructoren
 
Zitat:

Zitat von Robert Marquardt
Brauchst du wirklich zwei Konstuktoren? Geht es nicht vielleicht nur mit dem zweiten und einem Parameter mit Defaultwert?

Es ist ganz klar was bei "inherited Create(AOwner)" aufgerufen wird. Es wird der Konstruktor von TMyForm aufgerufen. Falls Du dort nicht ebenfalls an den Konstruktoren spielst, hat diese Klasse nur einen Konstruktor. Selbst wenn es mehrere Konstruktoren gibt, sichert Delphi ab das es immer eindeutig bleibt. es gibt Fehlermeldungen falls die Deklaration der overloaded Konstruktoren/Methoden nicht eindeutig ist.

Sorry, dass sind meine C++-Altlasten, es ist mir klar, dass man das ganze auch anders lösen kann :-D
Es wird nun langsam Licht im Dunkeln. TMyForm hat nur einen Konstruktor, von daher ist ab da für Delphi wieder alles klar.

Mir ist nur nicht klar, warum die Reihenfolge "overload; override;" für Delphi wichtig ist. Aber eigentlich verdeckt doch ein "overload" den originalen Konstruktor, oder nicht?
Von daher hätte ich erwartet, dass eine Kombination von beiden gar nicht zulässig sein dürfte, oder?

Zitat:

Zitat von SirThornberry
überschreiben des alten constructors muss sein damit die ide weiterhin den TComponent-Nachfahren erzeugen kann.
Allerdings würde ich das dann auch etwas anders machen. Und zwar im überschriebenen Constructor einfach den neuen Constructor aufrufen
Delphi-Quellcode:
constructor TTextEditor.Create(AOwner : TComponent);
begin
  Create(AOwner, StandardwertFuerlNEm);
end;

Hmmmm, irgendwie habe fehlt mir bei diesem Konstrukt die (visuelle) Information, dass es sich dann um den Konstruktor der Elternklasse handelt.

SirThornberry 13. Jun 2007 14:28

Re: Verwirrung mit override/overload bei Constructoren
 
eben mit overload sagst du dem compiler das du eine zweite methode mit gleichem namen hast. Da du aber von einer klasse abgeleitet hast welche bereits eine virtuelle Methode mit dem Namen und den gleichen Parameter hat verdeckst du diese (daher auch die Warnung des Verdeckens). Mit einem Cast auf die Vorgängerklasse könnte man also weiterhin die verdeckte Methode aufrufen. Die Warnungen und Fehler haben alle ihre Rechtigkeit und sind auch logich (zumindest aus meiner Sicht)

Robert Marquardt 13. Jun 2007 14:36

Re: Verwirrung mit override/overload bei Constructoren
 
Man sollte mehrere Konstruktoren vermeiden. Man verliert dabei naemlich die Kompatibilitaet zum C++ Builder.
es gibt allerdings doch einige lustige Anwendungsmoeglichkeiten wie einen privaten Konstruktor. Man leitet den normalen Konstruktor ab und wirft im Konstruktor eine Exception. Damit wird der normale Konstruktor unbenutzbar. Create ist bei TObject naemlich public und die Sichtbarkeit wird man nicht mehr los. Nun kann man einen privaten Konstruktor implementieren: Somit ist es unmoeglich Objekte dieser Klasse in anderen Units zu instantiieren. Man braucht dann natuerlich eine Factory-Klasse in der gleichen Unit die das uebernimmt.

SirThornberry 13. Jun 2007 14:45

Re: Verwirrung mit override/overload bei Constructoren
 
wenn man aber eine exception im Standardconstructor wirft kann man die Componente nicht mehr automatisch erstellen lassen, also nicht mehr zur Designzeit auf dem Formular plazieren.

hsg 13. Jun 2007 14:47

Re: Verwirrung mit override/overload bei Constructoren
 
Zitat:

Zitat von SirThornberry
eben mit overload sagst du dem compiler das du eine zweite methode mit gleichem namen hast. Da du aber von einer klasse abgeleitet hast welche bereits eine virtuelle Methode mit dem Namen und den gleichen Parameter hat verdeckst du diese (daher auch die Warnung des Verdeckens). Mit einem Cast auf die Vorgängerklasse könnte man also weiterhin die verdeckte Methode aufrufen. Die Warnungen und Fehler haben alle ihre Rechtigkeit und sind auch logich (zumindest aus meiner Sicht)

Ich habe aber in der "overload; override;" Variante keine Warnung, sondern der Compiler ist sehr glücklich mit meinem Source.
Habe ich nur das overload stehen, wird der originale Konstruktor verdeckt (deswegen dann ja auch die entsprechende Warnung), aber mit dem override sage ich doch normalerweise: da gibt es was in der Original-Klasse, bitte berücksichtige das auch....

Mein Verständnisproblem ist also momentan: verdecke ich den original Konstruktur (mittels overload) oder überschreibe ich ihn (mittels override).

Wenn ich mittels des ersten overload nur sage, da könnte evtl. noch eine Methode mit gleichem Namen geben, dann verstehe ich nicht das reintroduce im zweiten Konstruktor.

Ich glaube, ich schlafe erst einmal über dieses Thema (hab endlich Feierabend :mrgreen: )

Robert Marquardt 13. Jun 2007 14:53

Re: Verwirrung mit override/overload bei Constructoren
 
Zitat:

Zitat von SirThornberry
wenn man aber eine exception im Standardconstructor wirft kann man die Componente nicht mehr automatisch erstellen lassen, also nicht mehr zur Designzeit auf dem Formular plazieren.

Deshalb ist es fuer Komponenten auch nicht sinnvoll. Fuer Objekte aber schon.
Ich habe es bei meiner HID-Komponente gemacht, da dort ein DAU versucht hat Objekte, die ein Device repraesentieren, zu instantiieren. Das ist aber komplett sinnlos, da die Device-Objekte ausschliesslich von der Instanz der Controller-Komponente verwaltet werden.

SirThornberry 13. Jun 2007 14:54

Re: Verwirrung mit override/overload bei Constructoren
 
mit overload sagst du dem compiler einfach nur das es zwei methoden mit gleichem Namen gibt. Mit override überschreibst du eben die Methode aus der Klasse von der deine Klasse erbt. Wenn also jemand deine klasse auf die Vorgängerklasse castet und die Methode aufruft wird trotzdem deine neue Aufgerufen (trotz des casts) weil du sie eben überschrieben hast.

Und verdecken heißt einfach das du eine Methode nicht überschreibst diese dann aber nicht mehr aufrufbar ist außer man castet auf dein vorfahren wo noch nichts verdeckt ist.

@robert: in dem Fall scheint es mir dann auch mehr als sinnvoll so vorzugehen wie du es beschrieben hast.

shmia 13. Jun 2007 15:06

Re: Verwirrung mit override/overload bei Constructoren
 
Alle Klassen, die von TComponent abgeleitet wurden, haben einen virtuellen Konstruktor.
Dieser Konstruktor MUSS benützt werden, oder alles "geht in die Hosen".
Siehe Betrag #4 !!

hsg 14. Jun 2007 06:06

Re: Verwirrung mit override/overload bei Constructoren
 
Zitat:

Zitat von shmia
Alle Klassen, die von TComponent abgeleitet wurden, haben einen virtuellen Konstruktor.
Dieser Konstruktor MUSS benützt werden, oder alles "geht in die Hosen".
Siehe Betrag #4 !!

Er wird ja auch aufgerufen. Von daher ist alles im grünen Bereich.

Zitat:

Zitat von SirThornberry
mit overload sagst du dem compiler einfach nur das es zwei methoden mit gleichem Namen gibt. Mit override überschreibst du eben die Methode aus der Klasse von der deine Klasse erbt. Wenn also jemand deine klasse auf die Vorgängerklasse castet und die Methode aufruft wird trotzdem deine neue Aufgerufen (trotz des casts) weil du sie eben überschrieben hast.

Und verdecken heißt einfach das du eine Methode nicht überschreibst diese dann aber nicht mehr aufrufbar ist außer man castet auf dein vorfahren wo noch nichts verdeckt ist.

@robert: in dem Fall scheint es mir dann auch mehr als sinnvoll so vorzugehen wie du es beschrieben hast.

Also halten wir fest: overload sagt nicht, dass die Methode verdeckt wird, sondern diese Information bezieht der Compiler aus dem nicht vorhandenen override. Richtig?
Dann hat das alles auch Sinn.
Und nach einer erfrischenden Nacht, verstehe ich auch mittlerweile wieder was ich da mal programmiert habe :wink:


Zitat:

Zitat von Robert Marquardt
Man sollte mehrere Konstruktoren vermeiden. Man verliert dabei naemlich die Kompatibilitaet zum C++ Builder.
es gibt allerdings doch einige lustige Anwendungsmoeglichkeiten wie einen privaten Konstruktor. Man leitet den normalen Konstruktor ab und wirft im Konstruktor eine Exception. Damit wird der normale Konstruktor unbenutzbar. Create ist bei TObject naemlich public und die Sichtbarkeit wird man nicht mehr los. Nun kann man einen privaten Konstruktor implementieren: Somit ist es unmoeglich Objekte dieser Klasse in anderen Units zu instantiieren. Man braucht dann natuerlich eine Factory-Klasse in der gleichen Unit die das uebernimmt.

Wieso verliert man die Kompatibilität zum C++-Builder? Gerade in C++ hat man doch die Möglichkeit der mehreren Konstruktoren, von daher habe ich ja auch diese Programmierweise.
Aber die Idee mit der Exception im Default-Konstruktor gefällt mir.... muss ich mir merken.
Und es ist klar, dass man solche Sachen nicht für Komponenten verwendet.

Danke für die Diskussion.

Robert Marquardt 14. Jun 2007 07:11

Re: Verwirrung mit override/overload bei Constructoren
 
Bei C++ hat man nur genau einen Konstruktor. Delphi macht da ein paar Tricks die Konstruktoren doch abzubilden, aber es laesst sich nicht vollstaendig abbilden. Nicht immer aber gelegentlich laesst sich dann eine Komponente nicht im C++ Builder benutzen.

hsg 14. Jun 2007 13:09

Re: Verwirrung mit override/overload bei Constructoren
 
Zitat:

Zitat von Robert Marquardt
Bei C++ hat man nur genau einen Konstruktor. Delphi macht da ein paar Tricks die Konstruktoren doch abzubilden, aber es laesst sich nicht vollstaendig abbilden. Nicht immer aber gelegentlich laesst sich dann eine Komponente nicht im C++ Builder benutzen.

Nun verwirrst du mich sehr: Ein Beispiel:
Code:
class Auto
{
private:

  int   AnzahlRaeder;
  double Motorleistung;

public:

  // Defaultkonstruktor:
  Auto()
  {
    Motorleistung = 0.0;
    AnzahlRaeder = 4;
  }

  // überladener Konstruktor:
  Auto( double LeistungKW, int nRad = 4 )
  {
    Motorleistung = LeistungKW;
    AnzahlRaeder = nRad;
  }

};
sind doch zwei Konstruktoren, oder nicht? Und dies sind Beispiele aus Büchern, die keinerlei Bezug auf den C++-Builder haben.
Du hast in C++ genau einen Default-Konstruktor, da gebe ich dir recht. Wenn du ein überschreibenden Konstruktor erstellst, dann musst du auch den Default-Konstruktor definieren.
Aber du hast mehrere Konstruktoren.

Wo ich dir recht gebe, ist der Frust mit der VCL im C++-Builder, da die VCL auch im C++-Builder in Delphi geschrieben ist, sind gerade in der Komponentenentwicklung ein paar krampfige Fingerbruch-Übungen zu machen. Es kann sein, dass da auch was mit Konstruktoren zu Berücksichtigen gab, dazu arbeite ich schon wieder zu lange nicht mehr mit dem C++-Builder.


BTW: ein Vorschlag für DP07: Code-Tag für c++ wäre nett.......


Alle Zeitangaben in WEZ +1. Es ist jetzt 01:59 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