Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Delphi Meine Probleme mit Delphi-OOP ... (https://www.delphipraxis.net/166632-meine-probleme-mit-delphi-oop.html)

trebor90 22. Feb 2012 14:14

Meine Probleme mit Delphi-OOP ...
 
Hallo alle miteinander,

zur Historie
Ich begann in der Schule Delphi zu lernen, wie man das eben so macht; tippeln, verstehen, freuen :-D
Dann habe ich C, Java, C++ im Zuge des Studiums gelernt und kann jetzt OOP *freu* :-D
Nun kehre ich zu Delphi zurueck und gerate ganz schoen ins Straucheln ... :cry:


Meine Probleme
Ich habe also in C++ intensiver Klassengestaltung gelernt; ebenso virtuelle und abstrakte Methoden.
Aufgrund dessen kollidiere ich in Delphi mit den Worten >Verdecken/Verbergen< und >Ueberschreiben<.
Darueber hinaus programmiere ich ja auch in der Delphi IDE und diese erzeugt ja schonmal vorab eine ganze Menge Quelltext. Umso mehr knallt's dann, wenn ich versuche ein halbwegs vernuenftiges Klassenkonzept zu realisieren, ohne komplett in der vorgefertigten Kiste "herumzupfuschen" ...


Jetzt ganz genau
1.) Was ist der Unterschied zwischen Verbergen/Verdecken und Ueberschreiben? Ich habe widerspruechliche Dinge gelesen, nach welchen die verdeckten Methoden wieder mit inherited sichtbar gemacht werden koennen ...

2.) Ich habe Zwei Delphi-Formen, wobei ich die erste mit einem eigenen Konstruktor Create(Eigentuemer: TComponent; Kanalnummer: Integer) erzeuge und die Meldung bekomme:
[Warnung] Unit2.pas(25): Methode 'Create' verbirgt virtuelle Methode vom Basistyp 'TCustomForm'
Dabei hat meiner aber eine andere Signatur als der originaere --> Create(AOwner: TComponent)
Was soll ich tun (Bitte nicht nur sagen: reintroduce), ich will ihn ja eigentlich ueberladen, aber mit overload verschwindet die Warnung auch nicht, und Warnungen ignoriere ich nicht.

3.) Ist es ueberhaupt moeglich, ohne den von Delphi automatisch erzeugten Quelltext umzubauen, vernuenftig und streng objektorientiert zu programmieren? Es geht dabei primaer um GUIs.
Ich habe zum Beispiel erstmal die Klassen umbenannt, Zugriffspezifizierer gesetzt, globale Variablen fuer die Forms entfernt (>Form1: TForm1<), Konstruktoren geschrieben, automatische Erzeugungen (FormCreate) entfernt ...
Sieht jetzt so aus:

Delphi-Quellcode:
program Gehoerbildung;

uses
  Forms,
  Unit1 in 'Unit1.pas' {Hauptfenster},
  Unit2 in 'Unit2.pas' {GeraeteDialog};

{$R *.RES}

var Hauptfenster: THauptfenster;
begin
  Hauptfenster := THauptfenster.Create(nil);
   Application.Initialize;
   Application.CreateForm(THauptfenster, Hauptfenster);
  Application.Run;
end.
Delphi-Quellcode:
unit Unit1;

interface

uses
   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls,
   Buttons, MidiOut, Unit2;

type
  TTon = array [1..5] of Integer;
   THauptfenster = class(TForm)
   published
    AbsoluterTonCheckBox: TCheckBox;
    ZweiToeneCheckBox: TCheckBox;
    DreiToeneCheckBox: TCheckBox;
    VierklangCheckBox: TCheckBox;
    FuenfklangCheckBox: TCheckBox;
    HoheLageCheckBox: TCheckBox;
    MittlereLageCheckBox: TCheckBox;
      TiefeLageCheckBox: TCheckBox;
      GenugButton: TButton;
      MIDIDialogButton: TButton;
      WiederholungButton: TBitBtn;
      NeuerVersuchButton: TBitBtn;
      AufloesungButton: TBitBtn;
      CrashButton: TBitBtn;
      GehoerbildungLabel: TLabel;
      KleinC: TLabel;
      GrossC: TLabel;
      CEins: TLabel;
      CZwei: TLabel;
      CDrei: TLabel;
      Trennlinie1: TShape;
      Trennlinie2: TShape;
      Shape1: TShape;

   private
      FToene: TTon;
      FGeraeteDialog: TGeraeteDialog;
      FMidiOut: TMidiOutput;
      property GeraeteDialog: TGeraeteDialog read FGeraeteDialog write FGeraeteDialog;

   published
      procedure NeuerVersuchButtonClick(Sender: TObject);
      procedure WiederholungButtonClick(Sender: TObject);
      procedure AufloesungButtonClick(Sender: TObject);
      procedure CrashButtonClick(Sender: TObject);
      procedure GenugButtonClick(Sender: TObject);
      procedure MIDIDialogButtonClick(Sender: TObject);

      procedure FormCreate(Sender: TObject);
      procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
      procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
      procedure FormDestroy(Sender: TObject);

      procedure ErzeugeKlang(AnzahlToene: Integer);
      procedure BestimmeTiefstUndHoechstton(var Tiefster: Integer; var Hoechster: Integer);

   public
      function GetTon(Stelle: Integer): Integer;
      procedure SetTon(Stelle, NeuerTon: Integer);
      property Toene[Stelle: Integer]: Integer read GetTon write SetTon;
      property MidiOut: TMidiOutput read FMidiOut write FMidiOut;
   end;

implementation
--> Hier fehlen die globalen Variablen ...


4.) Wie verwendet man die Zugriffsspezifizierer (>Sichtbarkeitsattribute<) richtig? Musste zwangslaeufig das Meiste in published-Bloecke tun, dass das Programm ueberhaupt uebersetzt wird bzw. nicht abbricht aufgrund fehlender Klassenbestandteile. Aber das ist doch doof - steht doch total im Widerspruch zu Datenkapselung.


Nachtrag
Ich habe mich hier schon durch ein Paar Themen gelesen (mittels der Suche), ebenso durch mehrere Tutorien.
Doch habe ich's immer noch nicht ganz begriffen.
Bitte versteht also, wenn ich keine weiteren Verweise darauf suche, sondern es noch mal mit euren Worten erklaert bekommen moechte. Das bezieht sich insbesondere auf die Zugriffsspezifizierer und Ueberladen etc. .



Bis zur Hilfe,
Ri

himitsu 22. Feb 2012 14:24

AW: Meine Probleme mit Delphi-OOP ...
 
Das Überschreiben und Verdecken sollte es aber auch im C++ geben. (auch wenn dort die Syntax vielleicht etwas anders ist)

Inherited hat damit erstmal grundsätzlich garnichts zu tun.
Der Aufruf von inherited besagt nur, daß man an dieser Stelle die Methode eines Vorfahren und nicht eine "Eigene" aufrufen will
und das geht sowohl bei überdeckten, als auch bei überschriebenen Methoden.

Delphi-Quellcode:
type
  TMyClassA = class
    procedure A; overload; // überladen
    procedure A(i: Integer); overload;
    procedure X;
    procedure Y; virtual; // mit oder ohne abstract
    procedure Z; virtual; // mit oder ohne abstract
  end;

  TMyClassB = class(TMyClassA)
    procedure X; // verdeckt
    procedure Y; // verdeckt
    procedure Z; override; // überschrieben
  end;

var
  C: TMyClassA;
  D: TMyClassA;
  E: TMyClassB;

C := TMyClassB.Create;

C.Y; // TMyClassA.Y wird ausgeführt, da die Methode nur verdeckt, aber nicht überschrieben wurde.
C.Z; // TMyClassB.Z wird ausgeführt

C.Free;

C := TMyClassA.Create;
D := TMyClassB.Create;
E := TMyClassB.Create;

C.Y; // TMyClassA.Y
C.Z; // TMyClassA.Z

D.Y; // TMyClassA.Y
D.Z; // TMyClassB.Z

E.Y; // TMyClassB.Y
E.Z; // TMyClassB.Z

DeddyH 22. Feb 2012 14:31

AW: Meine Probleme mit Delphi-OOP ...
 
Und zum published: der Abschnitt ist für die Kommunikation mit dem Objektinspektor gedacht. Also muss folglich alles, was man bereits zur Designtime zuweisen will, in diesen Abschnitt. Außerdem werden Komponenten, die hier stehen, in die *.dfm aufgenommen und aus ihr geladen. Wenn man auf diesen Komfort verzichten kann/will, dann kann man sie auch z.B. in den private-Abschnitt verschieben, muss sie dann aber auch zur Laufzeit erzeugen/freigeben und alle Werte per Code zuweisen (inkl. der Events).

shmia 22. Feb 2012 14:50

AW: Meine Probleme mit Delphi-OOP ...
 
Ich geb Dir mal eine Teilantwort auf deine Fragen.
Also der Konstruktor von TComponent ist virtuell.
Damit ist auch der Konstruktor aller davon abgeleiteten Klassen (insbesondere TForm) auch virtuell.
Sobald ein virtueller Konstruktor existiert, ändern sich die Spielregeln für die Klassen (und alle davon abgeleiteten Klassen).
Wenn man nun einen anderen Konstruktor als den vordefinierten virtuellen Konstruktor benützt bekommt man das Problem dass der selbstdefinierte Konstruktor unter Umständen nicht aufgerufen wird.
Delphi-Quellcode:
// Beispielcode
// Hier wird ein Formular erzeugt aber dabei nur der virtuelle Standardkonstruktor aufgerufen
Application.CreateForm(TForm, Form1);
Daher gilt die Regel:
keine neuen Konstruktoren für Klassen definieren, die von TComponent abgeleitet sind!!
Nur diese Signatur ist erlaubt
Delphi-Quellcode:
public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;

himitsu 22. Feb 2012 16:44

AW: Meine Probleme mit Delphi-OOP ...
 
Zitat:

Zitat von DeddyH (Beitrag 1152365)
Und zum published: der Abschnitt ist für die Kommunikation mit dem Objektinspektor gedacht.

Zum Beispiel mit dem OI. Nicht nur für diesen. :angle:
Published legt erweiterte RTTI-Informationen an.

Nja, will man Designtime-Komponenten haben, muß man von TComponent erben.
TComponent ist im Modus {$M+} compiliert, womit "published" als Standardabschnitt aktiv ist. (wenn vorher kein private, public und Co. angegeben wurde, so wie in meinen Beispielklassen)
Ansonsten ist alles standardmäßig public.

trebor90 22. Feb 2012 17:29

AW: Meine Probleme mit Delphi-OOP ...
 
Hallo und danke erst einmal fuer die raschen Antworten.

Also zuersteinmal zum Verdecken und Ueberladen
Ich verstehe es nicht. Auch anhand des Beispiels nicht. Besser waere eine exakte Definition von Verbergen und Ueberschreiben im Zusammenhang mit Virtual (und ohne dieses).
Wir haben in C++ gelernt, dass es im Zuge der Vererbung zwei Moeglichkeiten gibt, sich auf eine bereits definierte Methode zu beziehen:
  • Ueberladen - Definition einer Methode mit bereits vorhandenem Namen aber anderer Signatur
  • Ueberschreiben - Definition einer bereits vorhandenen Methode (die ueberschriebene steht dann noch immer zur Verfuegung) - Dabei ist virtual NICHT ZWINGEND
Virtual wird erst erforderlich, wenn dynamisches Binden gewuenscht ist, also erst zur Laufzeit entschieden wird, welche der vielen "gleichen" Methoden ausgefuehrt werden soll (aber auch nur bei Zeigern und Referenzen). Ohne virtual wird ansonsten immer die Methode des Datentyps ausgefuehrt, welche die das Objekt beinhaltende Variable hat, unabhaengig davon, welchen Datentyp das Objekt in Wirklichkeit hat ...
Hier scheint das naders zu sein: Hier muss zum Ueberladen wohl immer die Basismethode virtual sein ...
--> Dringender Erklaerungsbedarf zu dem ganzen Komplex (in Form einer sauberen, klar abgegrenzten Definition)


Zum Published
Ok, das mit dem Objektinspektor wusste ich.
Heisst das aber, dass auch alle Methoden, die durch die Form-Komponenten benutzt werden (Ereignisbehandlungsroutinen, z. B. ButtonClick, EditKeydown ...) auch published sein muessen?? Bzw. Methoden, welche von dieses Ereignisbehandlungsroutinen benutzt werden??? Das waere ja ein Schlag in die Magengrube der Objektorientierung ...
So waeren ja nur noch Felder und Methoden geschuetzt, welche nichts mit der Form zu tun haetten.
Ist das richtig?
(Ausgangspunkt ist natuerlich, dass ich mit dem Objektinspektor arbeiten will)


Zum Virtuellen Konstruktor
Also dass mein eigens entwickelter Konstruktor nicht aufgerufen wird, halte ich fuer unwahrscheinlich.
Ich rufe ihn ja selbst explizit auf. In einer anderen Form. Also meine erste Form erzeugt die zweite mit dem selbstentwickelten Konstruktor. Dabei entsteht die Warnung. Auch bei overload (da ich ihn ja ueberlade).
Aehnlich verfahre ich auch mit der ersten Form: Dafuer erstelle ich im Hauptprogramm eine lokale Variable, welche ich mit einem neuen Form-Objekt durch den Standardkonstruktor Create(AOwner: TComponent) initialisiere; danach kommt erst CreateForm(...).
Bitte dafuer noch einmal meine Ueberarbeitung des Hauptprogramms im ersten Beitrag ansehen.
Habe wie gesagt ALLE globalen Variablen (*Gaensehaut bekomm*) entfernt und eine lokale Variable fuer das Hauptprogramm angelegt.

Aber zu der Aussage, die du triffst, >shmia<:
Dann koennte ich ja alle Felder, die ich einer Form hinzufuege nur von aussen "nach-initialisieren", mit Set-Methoden, denn Konstruktoren darf ich laut deiner Aussage dafuer nicht schreiben.
Auch das waere ein Verstoss gegen das Prinzip der OOP. Jedes Objekt soll sich selbst verwalten und die Konsistenz der eigenen Daten sicherstellen.


Entschuldigt, wenn ich rechthaberisch klinge, aber genau deswegen eroeffnete ich das Thema, weil es momentan heftige Kollisionen mit meinem bisherigen Verstaendnis der OOP (aus anderen Sprachen) gibt.



Bis dann,
Ri

shmia 22. Feb 2012 18:09

AW: Meine Probleme mit Delphi-OOP ...
 
Zitat:

Zitat von trebor90 (Beitrag 1152384)
Zum Virtuellen Konstruktor
Also dass mein eigens entwickelter Konstruktor nicht aufgerufen wird, halte ich fuer unwahrscheinlich. Ich rufe ihn ja selbst explizit auf.

Jede Komponente kann aber auch von der VCL erzeugt werden.
Dieser Weg wird in der Praxis weit häufiger benützt als das explizite Aufrufen des Konstruktors.
Jedes Label, Editfeld, Menü,... wird ja normalerweise unter Zuhilfenahme der DFM-Datei dynamisch zur Laufzeit erzeugt.
Genau aus diesem Grund wurde ja für Komponenten ein virtueller (Standard-)Konstruktor eingeführt.
Wenn deine Komponente eine weiteren Konstruktor hat, dann wird dieser von der VCL ignoriert.
Daraus kann man nur die Schlussfolgerung ziehen, dass es einfacher und sicherer ist Parameter nicht über den Konstruktor sondern über Properties dem Objekt bekannt zu machen.
Delphi-Quellcode:
// Negativbeispiel
TDoppeltGemoppelt = class(TBasisComponent)
private
  FAnzahl : integer;
public
  // virtueller Standard Konstruktor
  constructor Create(AOwner:TComnponent); override;

  // nicht-standard Konstruktor
  constructor Create(anzahl:integer);
published
  property Anzahl:integer read FAnzahl write FAnzahl default 100;
end;


constructor TDoppeltGemoppelt.Create(AOwner:TComnponent); override;
begin
  inherited; // vererbten Konstruktor aufrufen
  FAnzahl := 100; // Defaultwert für property Anzahl setzen
end;

constructor TDoppeltGemoppelt.Create(anzahl:integer);
begin
  // wir müssen auf jeden Fall den Standard Konstruktor aufrufen
  // wenn das vergessen wird, gibt es Probleme
  Create(nil {Owner ist hier unbekannt});
  FAnzahl := anzahl;
end;

.....

var
  a, b : TDoppelGemoppelt;
begin
  a := TDoppelGemoppelt.Create(42);

  b:= TDoppelGemoppelt.Create(nil);
  b.Anzahl := 42;
Um das Objekt "b" zu initialisieren benötigt man eine Zeile mehr als für Objekt "a".
Wenn aber der eigene Konstruktor so wenig Zusatznutzen bringt ist es besser ihn ganz weg zu lassen und immer nur mit dem Standard Konstruktor und Properties zu arbeiten.

Komponenten in Delphi sind in der Hinsicht genau gleich wie JavaBeans.

MGC 22. Feb 2012 21:45

AW: Meine Probleme mit Delphi-OOP ...
 
Zitat:

Zitat von trebor90 (Beitrag 1152384)
Hallo und danke erst einmal fuer die raschen Antworten.
Dabei entsteht die Warnung. Auch bei overload (da ich ihn ja ueberlade).

An genau dieser Stelle hast Du die oben aufgeführten Beispiele nicht genau angesehen. Das Überladen von Funktionen und Prozeduren, den sogenannten Methoden eines Objekts wird im Deklarationsteil des Objekts abgegeben und unterstützt die Polymorphie. Overload darf nicht mit dem Überschreiben eines Konstruktors oder Destruktors, bzw. jeder anderen virtuellen Methode verwechselt werden. Beim Überladen wird eine weitere oder auch mehrere weitere Methode/Methoden eingeführt, die eine unterschiedliche Parameterliste aufweisen.

Siehe auch bei Delphi-Treff folgendes:
Zitat:

[...]
Prozeduren und Funktionen überladen

In Delphi ist es möglich, im selben Gültigkeitsbereich mehrere Routinen mit identischem Namen zu deklarieren. Dieses Verfahren wird "Überladen" genannt.

Überladene Routinen müssen mit der Direktiven overload deklariert werden und unterschiedliche Parameterlisten haben.

Delphi-Quellcode:
  function Divide(x, y: real): real; overload;
  begin
    result := x / y;
  end;

  function Divide(x, y: integer): integer; overload;
  begin
    result := x div y;
  end;
Diese Deklarationen definieren zwei Funktionen namens Divide, die Parameter unterschiedlicher Typen entgegennehmen. Wenn Divide aufgerufen wird, ermittelt der Compiler die zu verwendende Funktion durch Prüfung des übergebenen Parametertyps.

Divide(6.0, 3.0) ruft beispielsweise die erste Divide-Funktion auf, da es sich bei den Argumenten um reelle Zahlen handelt, auch wenn der Nachkommateil Null ist.

Überladene Methoden müssen sich deshalb entweder in der Anzahl der Parameter oder in den Typen dieser Parameter signifikant unterscheiden.
Wenn Du allerdings eine virtuelle Methode, bzw. einen Konstruktor oder Destruktor überschreiben möchtest, so verwendest Du den Befehl OVERRIDE.
Um sicherzustellen das dennoch Dein Objekt erzeugt wird, rufst Du die ursprüngliche Methode mit inherited auf. Also beim Konstruktor inherited aufrufen und dann Deinen eigenen Code abarbeiten lassen. Beim Destruktor zuerst Deinen eigenen Code ablaufen lassen udn inherited zum Schluss (Erklärt sich von selbst wenn man bedenkt, dass man in nicht vorhandenen Objekten keine Änderungen durchführen kann).

Delphi-Quellcode:
TBasisClass = TObject
  constructor Create(AOwnder: TComponent); virtual;
  destructor Destroy; virtual;
end;

TMyClass = TBasisClass
  constructor Create(AOwner: TComponent); override;
  destructor Destroy; override;
  function DoSomeThing(Left,Right: Integer): Boolean; Overload;
  function DoSomeThing(Left,Right: String; Up,Down: Integer): Boolean; Overload;
end;

constructor TMyClass.Create(AOwner: TComponent);
begin
  inherited;
  { Eigebner Quellcode der abgearbeitet werden soll }
end;

destructor TMyClass.Destroy;
begin
  { eigener Code der abgearbeitet werden soll }
  inherited;
end;

function TMyClass.DoSomeThing(Left,Right: Integer): Boolean;
begin
  { DoSomeThing }
end;

function TMyClass.DoSomeThing(Left,Right: String; Up,Down: Integer): Boolean;
begin
  {DoSomeThingElse }
end;

trebor90 23. Feb 2012 13:28

AW: Meine Probleme mit Delphi-OOP ...
 
Warum glaubt mir denn keiner ...?? :cry:

Das, was ihr sagt, habe ich doch weiter oben alles selbst schon beschrieben ...
Ich weiss, was Ueberladen und Ueberschreiben ist ...

Zitat:

Zitat von trebor90
Wir haben in C++ gelernt, dass es im Zuge der Vererbung zwei Moeglichkeiten gibt, sich auf eine bereits definierte Methode zu beziehen:

Ueberladen - Definition einer Methode mit bereits vorhandenem Namen aber anderer Signatur
Ueberschreiben - Definition einer bereits vorhandenen Methode (die ueberschriebene steht dann noch immer zur Verfuegung) - Dabei ist virtual NICHT ZWINGEND

Zitat:

Zitat von MGC
Wenn Du allerdings eine virtuelle Methode, bzw. einen Konstruktor oder Destruktor überschreiben möchtest, so verwendest Du den Befehl OVERRIDE.

--> Will ich NICHT. Ich will ihn ueberladen, eine weitere Variante des Konstruktors der Form hinzufuegen ...

Delphi-Quellcode:
constructor Create(Eigentuemer: TComponent; DieKanalnummer: Integer); overload;

constructor TGeraeteDialog.Create(Eigentuemer: TComponent; DieKanalnummer: Integer);
begin
   inherited Create(Eigentuemer);
   Kanalnummer := DieKanalnummer;
end;
--> Das ist, was ich will. Und die Warnung bleibt bestehen, obwohl ich nix verdecken will, nur ueberladen.

Zitat:

Zitat von shmia
Wenn deine Komponente eine weiteren Konstruktor hat, dann wird dieser von der VCL ignoriert.

--> Das denke ich nicht. Ich stelle nochmal mein Hauptprogramm ein:

Delphi-Quellcode:
var Hauptfenster: THauptfenster; //globale Variable in Unit1 geloescht!!!!! Hier LOKALE Variable angelegt
begin
  Hauptfenster := THauptfenster.Create(nil); //selbststaendig den Standardkonstruktor der ersten Klasse eingestellt
   Application.Initialize;
   Application.CreateForm(THauptfenster, Hauptfenster); //Hier wird die erste Form durch VCL initialiserst/virtueller Standard-Konstuktor
   //Hier stuende noch eine Zeile, wo die zweite Form initialisiert wuerde, aber die habe ich geloescht, denn das macht mein eigener explizit aufgerufener Konstruktor in der ersten Form; die zweite Form ist ein Attribut der ersten Form
  Application.Run;
end.
Vielleicht nochmal zum Verstaendnis:
Mein Programm besteht aus zwei Forms, eine wird im Hauptprogramm durch die VCL initialisert (wie oben zu sehen), die andere wird als Attribut der ersten mit einem expliziten Konstruktor UND NICHT DURCH DIE VCL erstellt. Dabei entsteht die Warnung.

himitsu 23. Feb 2012 13:48

AW: Meine Probleme mit Delphi-OOP ...
 
Delphi-Quellcode:
Hauptfenster := THauptfenster.Create(nil); // hier erstellst du manuell eine Instanz von TForm.
Application.Initialize; // und daß Erstellen auch noch vor dem Initialisieren der VCL
Application.CreateForm(THauptfenster, Hauptfenster); // und hier wird nochmal ein eine Instanz erstellt.
PS: Jetzt steht in Hauptfenster der Instanzzeiger der automatisch erstellten Instanz, aber (da Visible der Formulare standardmäßig) False ist, wird hier eventuell nur das zuerst erstellte Fenster angezeigt und nicht das jenes, welches in der Variable gespeichert ist.

trebor90 23. Feb 2012 13:55

AW: Meine Probleme mit Delphi-OOP ...
 
Ja, ok das stimmt.
Diesen ersten Konstruktor kann ich entfernen. Da ist richtig.
Aber es geht ja auch darum, dass ich hier eine lokale Variable erstellt habe. Dazu sagt z. B. niemand was.
Und es ging ja auch mehr um den ueberladenen Konstruktor der anderen Form, denn der verursacht die Warnung.

Und naja, um die ganzen anderen Probleme die bisher ungenuegende Beruecksichtigung fanden.
:-)

Bummi 23. Feb 2012 14:00

AW: Meine Probleme mit Delphi-OOP ...
 
Hat was damit zu tun das Create urspünglich virtual deklariert wurde

Delphi-Quellcode:
  TMyClass=Class
    Procedure TuWas(a:Integer);
    Procedure TuWasvirtual(a:Integer);virtual;
  End;
  TMyClass1=Class(TMyClass)
    Procedure TuWas(a:Integer;b:Integer);overload;
    Procedure TuWasvirtual(a:Integer;B:Integer);overload;
  End;
führt auch zu

[DCC Warnung] Unit2.pas(16): W1010 Methode 'TuWasvirtual' verbirgt virtuelle Methode vom Basistyp 'TMyClass'

trebor90 23. Feb 2012 14:27

AW: Meine Probleme mit Delphi-OOP ...
 
Obwohl ich sie eigentlich gar nicht verbergen moechte, sondern nur ueberladen?

Jumpy 23. Feb 2012 14:57

AW: Meine Probleme mit Delphi-OOP ...
 
Mal als Kommentar von der Seite, von jemandem, der OOP-mäßig ja noch in die Schule geht und da mit C# rumhampeln muss. Wenn du in einer abgeleiteten Klasse den Konstruktor überlädtst, dann überschreibst du ihn auch, mein ich. Sprich also du musst (zumindes in C# machen wir das so) in der abgeleiteten Klasse erst den Standardkontruktor überschreiben mit einem Standardkonstruktor und dann diesen überladen. Vllt. verwechsle ich das aber auch.

MGC 23. Feb 2012 17:22

AW: Meine Probleme mit Delphi-OOP ...
 
@Jumpy: Genauso ist es meines Erachtens auch korrekt. Da der Konstruktor in der Basislkase als virtuell deklariert wurde muss er in der abgeleiteten Klasse zuerst überschrieben werden (mit override) und wenn man dann weitere Konstruktoren mit variieender Parameterliste hinzufügen will, werden diese überladen (overload), so habe ich es auch gelernt. In wie weit man hinter den ersten Konstruktor allerding override und overload zugleich setzen kann, weiß ich jetzt aus dem Stehgreif auch nicht, werde ich aber mal testen.

@trebor90: In welche Variable (lokal oder global) Du ein Objekt erzeugst interresiert doch den Konstruktor nicht.
Aber ich verstehe jetzt auch nicht ganz, wieso Du solche Probleme mit Polymorphie hast, gehört doch auch zur OOP und nennt sich auch späte Bindung oder Overriding und ist somit nicht rein delphispezifisch.
Kann man z.B. auch auf Wikipedia nachlesen...
Zitat:

Polymorphie [Bearbeiten]

→ Hauptartikel: Polymorphie (Programmierung)

Unter bestimmten Voraussetzungen können Algorithmen, die auf den Schnittstellen eines bestimmten Objekttyps operieren, auch mit davon abgeleiteten Objekten zusammenarbeiten.

Geschieht dies so, dass durch Vererbung überschriebene Methoden an Stelle der Methoden des vererbenden Objektes ausgeführt werden, dann spricht man von Polymorphie. Polymorphie stellt damit eine Möglichkeit dar, einer durch ähnliche Objekte ausgeführten Aktion einen Namen zu geben, wobei jedes Objekt die Aktion in einer für das Objekt geeigneten Weise implementiert.

Diese Technik, das so genannte Overriding, implementiert aber keine universelle Polymorphie, sondern nur die sogenannte Ad-hoc-Polymorphie.
Viele Grüße.

trebor90 23. Feb 2012 19:16

AW: Meine Probleme mit Delphi-OOP ...
 
Also dass ich eine virtuelle Methode bzw. einen Konstruktor erst in einer abgeleiteten Klasse ueberschreiben muss, dass ich sie/ihn dann ueberladen kann - davon habe ich noch nie etwas gehoert.
Ich kann doch Sachen ueberladen, ohne sie vorher ueberschreiben zu muessen (egal ob virtuell oder nicht).

Und dass ich das mit den globalen und lokalen Variablen anspreche:
Hat nix mit dem Konstruktor zu tun. Nur, dass ich nicht mit grossen Fensterobjekten ueber globale Variablen agieren moechte, sondern, wie es sich gehoert, sie in lokale packe. Und darauf hinwies.
Die Frage waere naemlich, wie "ihr" das so macht? Lasst ihr den vorgefertigten Delphi-Quelltext so

Delphi-Quellcode:
var
  Form1: TForm1

implementation

...
oder aendert ihr das im Hauptprogramm in eine lokale Variable?

--

mkinzler 23. Feb 2012 19:47

AW: Meine Probleme mit Delphi-OOP ...
 
Zitat:

oder aendert ihr das im Hauptprogramm in eine lokale Variable?
Wenn dann in eine Eigesnchaft einer Klasse.
Zitat:

Also dass ich eine virtuelle Methode bzw. einen Konstruktor erst in einer abgeleiteten Klasse ueberschreiben muss, dass ich sie/ihn dann ueberladen kann - davon habe ich noch nie etwas gehoert.
Man muss eine Methode nur überschreibnen, wenn diese in der Superklaase abstrakt ist. (In Delphi auch nur, wenn man diese Nutzen möchte). Normale Methoden muss man nicht Überschreiben; virtual erlaubt das nur.
Zitat:

Ich kann doch Sachen ueberladen, ohne sie vorher ueberschreiben zu muessen (egal ob virtuell oder nicht).
Jein, da man nicht virtuelle Methoden ja nicht überschreiben kann.

einbeliebigername 23. Feb 2012 20:17

AW: Meine Probleme mit Delphi-OOP ...
 
Hallo,

ich gebe auch mal meinen Senf zum Thema überladen von virtuellen Methoden dazu.

Entweder so:
Delphi-Quellcode:
  TTest1= class
    procedure Test; virtual;
  end;

  TTest2= class(TTest1)
    procedure Test(const A: Integer); reintroduce; overload;
  end;
Oder so:
Delphi-Quellcode:
  TTest3= class
    procedure Test; overload; virtual;
  end;

  TTest4= class(TTest3)
    procedure Test(const A: Integer); overload;
  end;
einbeliebigername.

trebor90 23. Feb 2012 21:49

AW: Meine Probleme mit Delphi-OOP ...
 
@einbeliebigername:
Ok, dann ist das anders als zum Beispiel in C++. Da muss man Methoden nicht erst reintroducen, um eine Methode einer Basisklasse ueberladen zu koennen. Man ueberlaedt sie und - fertig.
Das heisst also, der Designer der Basisklasse legt in Delphi fest, ob man seine Methoden "einfach so" (ohne reintroduce) ueberladen kann?? Indem er hinter die betreffenden ein overload setzt????!

@mkinzler:
Nein. Warum denn eine Klasseneigenschaft?! Du hast mich wohl falsch verstanden. Ich rede nicht von pubnormalen Eigenschaften die faelschlicherweise oft als globale Variablen deklariert werden. Ich rede von einer Form, einem Fenster. Das Hauptfenster zum Beispiel, dass als erstes in der Applikation gestartet wird, muesste also eine lokale Variable der Hauptfunktion sein.
(Bitte schaut euch dazu meine Quelltexte an ...)
Sicherlich kann das jedes weitere Fenster eine Eigenschaft des Hauptfensters (und keine globale Variable) sein.

Zitat:

Zitat von mkinzler
Man muss eine Methode nur überschreibnen, wenn diese in der Superklaase abstrakt ist. (In Delphi auch nur, wenn man diese Nutzen möchte). Normale Methoden muss man nicht Überschreiben; virtual erlaubt das nur.

--> Ok, warum blabbert mich dann aber Delphi mit Warnungen zu, obwohl ich Create UEBERLADE mit overload? Welches eben virtual ist, und welches ich nicht verdecken moechte (was mir aber der Compiler unterstellt).

Zitat:

Zitat von trebor90
Ich kann doch Sachen ueberladen, ohne sie vorher ueberschreiben zu muessen (egal ob virtuell oder nicht).

Zitat:

Zitat von mkinzler
Jein, da man nicht virtuelle Methoden ja nicht überschreiben kann.

Was??
Ich will doch gar nix ueberSCHREIBEN.
Ich wollte damit sagen, dass ich Methoden ueberladen kann. Dazu muss ich sie nicht ueberschreiben.
Egal ob sie virtuell sind oder nicht.
Ueberladen ohne sie vorher zu ueberschreiben, wie es einige sagen.
Ich muss Methoden nicht erst ueberschreiben, dass ich sie hinterher ueberladen kann.

--> Und in C++ muss eine Methode auch nicht virtuell sein, dass ich sie ueberschreiben kann. Das geht auch ohne.


Problem aber immer noch:
Was ist der Unterschied zwischen Verdecken und Ueberschreiben??
Ich kenne sowas wie "Verdecken" gar nicht.

MGC 23. Feb 2012 23:31

AW: Meine Probleme mit Delphi-OOP ...
 
So, jetzt wirds richtig konfus.

Also erstmal zum Thema lokale Variable:
Wie muss ich das verstehen? Du ordnest Deinem MainForm eine lokale Variable unter, in die Du dan diese MainForm erzeugen willst? Meinst DU damit, dass Du diese Variable als Feld in Deinem MainForm hinterlegst? Dann würdest Du ja Dein Form in sich selbst erzeugen und kannst eigentlich erst richtig auf Dein Feld zugreifen, wenn Du Dein Form (das Objekt) erzeugt hast... Das klingt seltsam. Meine MainForm ist grundsätzlich in einer globalen Variable hinterlegt, es sei denn ich würde das MainForm aus einem eigenen Objekt heraus erzeugen und mich selbst um die Verwaltung (erzuegen, verwalten, freigeben) kümmern, bzw. einen Parent angeben, ansonsten überlasse ich das vollkommen Delphi.

Dann zum Thema überladen und reintroduce. Auf reintroduce bin ich nicht eingegangen, da Du es unbedingt vermeiden wolltest, weshalb auch immer.
Sieh das ganze mal aus der Sicht des Compilers. Du hast ein, von einer Basisklasse abgeleitetes, Objekt (in OOP ganz normal) dessen Konstruktor in der Basisklasse als virtuell deklariert ist (nicht abstrakt, sonst müsstest Du es auf jedenfall selbst beleben, siehe z.B. TStrings). Wenn Du nun einen eigenen Konstruktor Create erzeugst und nicht angibst, dass es sich um eine mögliche Erweiterung Deinerseits zum ursprünglichen Create, dann gibt es jetzt zweimal Create und der Compiler warnt Dich, dass Dein, in Deiner abgeleiteten Klasse angegebenes Create, den originalen virtuell deklarierten Konstruktor Create verdeckt. Da Du aber beim überladen den Befehl overload hinter beide Konstruktoren setzen musst, ist es zwingend erforderlich dieses dem Compiler mitzuteilen. Daher kannst Du entweder bereits den originalen Konstruktor überschreiben und erweitern, ein override udn ein overload hinzufügen und dann einen weiteren Konstruktor mit overload hinzusetzen, wenn seine Parameterliste sich vom ersten unterscheidet. Willst Du den originalen Konstruktor nicht erweitern, dann teilst Du dem Comiler mit reintroduce udn overload mit, dass es sich bei dem ersten Konstruktor um den originalen aus der Basisklasse handelt und das Du weitere überladene Konstruktoren für andere Zwecke hinzufügst.

In wie weit es in einer anderen Sprache anders gehandhabt wird ist uninteressant, ich kann auch nicht diskutieren, dass ich es in C++ blöd finde immer diese {} zu setzen, wo das doch in Delphi auch nicht so ist und aus meiner Sicht nur die Lesbarkeit des Quellcodes verschlechtert.

Innerhalb der Zeit, in der wir hier unzählige Symbole aneinandergefügt haben um miteinander zu diskutieren, hätte man zigmal reintroduce schreiben können, egal ob man es blöd findet oder nicht.

Aber bitte diese Antwort nicht bös auffassen, sie ist nicht so polemisch gemeint, wie sie vielleicht klingen mag, wenn man sich in ein Thema hineingesteigert hat.

Viele Grüße.

himitsu 24. Feb 2012 01:20

AW: Meine Probleme mit Delphi-OOP ...
 
Liste der Anhänge anzeigen (Anzahl: 1)
Praktisch gesehn, werden diese globalen Form-Variablen garnicht benötigt, welche Delphi standardmäßig anlegt.

Ich würde mir wünschen, wenn es dieses CreateForm auch ohne diesen Var-Parameter geben würde. Aber mit einer temporären Variable in der DPR, könnte man dieses auch lösen.
Vorallem in einem Programm mit nur einem automatisch erstellten Form, gibt es IMHO absolut keine Daseinsberechtigung für diese Variable und ohne diese gäbe es viele (Anfänger)Probleme ganicht erst.

PS: Das angehängteDemoprojekt enthält einen Fehler, wie es genau so schon vorgekommen ist, bei einem Anfänger/Schüler, letztes Jahr hier in der DP.
Und er zeigt ein großes Problem, welches mit globalen Variablen auftreten kann, wenn sie nicht eindeutig verwendet, sondern mehrmals und/oder an mehreren Stellen genutzt werden.

Ach ja, ich suche noch eine einfache Demo, für eine globale Zählvariable, welche in mehreren Funktionen genutzt werden und sich so gegenseitig beeinflussen, was mit lokalen Schleifenvariablen nicht passieren würde. Falls jemand was kennt.... (mit ist der Thread aus'm letzten/vorletzen Jahr nicht wieder eingefallen, wo sowas mal aufgetreten ist)

Gustav.R 24. Feb 2012 02:43

AW: Meine Probleme mit Delphi-OOP ...
 
Zitat:

Zitat von himitsu (Beitrag 1152602)

Ach ja, ich suche noch eine einfache Demo, für eine globale Zählvariable, welche in mehreren Funktionen genutzt werden und sich so gegenseitig beeinflussen, was mit lokalen Schleifenvariablen nicht passieren würde. Falls jemand was kennt....

Dir ist schon klar, daß Du müde bist:
http://www.youtube.com/watch?v=ODlmEjZ8UFA

:wink:

freak4fun 24. Feb 2012 10:25

AW: Meine Probleme mit Delphi-OOP ...
 
Vielleicht hilft das hier weiter: Klick! :)

einbeliebigername 24. Feb 2012 10:29

AW: Meine Probleme mit Delphi-OOP ...
 
Hallo,

Zitat:

Zitat von MGC (Beitrag 1152598)
Daher kannst Du entweder bereits den originalen Konstruktor überschreiben und erweitern, ein override udn ein overload hinzufügen und dann einen weiteren Konstruktor mit overload hinzusetzen, wenn seine Parameterliste sich vom ersten unterscheidet.

Hast du das schon mal gemacht. Also ich habe das jetzt bei dir, aufbauen auf meinem obigen Code, so verstanden, das folgendes keine Warnung bringen soll:
Delphi-Quellcode:
  TTest5= class(TTest1)
    procedure Test; overload; override;
    procedure Test(const A: Integer); overload;
  end;
Kommt aber trotzdem die Warnung:
Code:
[DCC Warnung] MethodTracerUnit1.pas(32): W1010 Methode 'Test' verbirgt virtuelle Methode vom Basistyp 'TTest1'
Zitat:

Zitat von trebor90 (Beitrag 1152592)
@einbeliebigername:
Ok, dann ist das anders als zum Beispiel in C++. Da muss man Methoden nicht erst reintroducen, um eine Methode einer Basisklasse ueberladen zu koennen. Man ueberlaedt sie und - fertig.
Das heisst also, der Designer der Basisklasse legt in Delphi fest, ob man seine Methoden "einfach so" (ohne reintroduce) ueberladen kann?? Indem er hinter die betreffenden ein overload setzt????!

Bei C bzw. C++ ist alles ein wenig anders. In C ist jede Funktion und somit in C++ auch jede Methode sofort überladbar. Das heißt man kann folgendes machen:
Code:
  void Test;
  void Test(int A);
In Delphi ist jede normale Funktion, Prozedur, Methode nicht überladbar. Will man überladen muss man bei jeder Version ein overload mit angeben. Folgendes geht deswegen so nicht:
Delphi-Quellcode:
    procedure Test;
    procedure Test(const A: Integer);
Der Kompilier wirft da einen Fehler. Auch so:
Delphi-Quellcode:
    procedure Test;
    procedure Test(const A: Integer); overload;
und so gibt es einen Fehler:
Delphi-Quellcode:
    procedure Test; overload;
    procedure Test(const A: Integer);
Erst so funktioniert das Überladen:
Delphi-Quellcode:
    procedure Test; overload;
    procedure Test(const A: Integer); overload;
Und weil das auch bei Vererbung so ist, braucht man für jede andere Version des Create-Constructors bei Komponenten ein
Delphi-Quellcode:
reintroduce;
.

Zitat:

Zitat von trebor90 (Beitrag 1152592)
--> Und in C++ muss eine Methode auch nicht virtuell sein, dass ich sie ueberschreiben kann. Das geht auch ohne.

Kannst du das mal bitte mit einem Beispiel verdeutlichen wie das funktionieren soll. Bei mir ist C++ schon eine Weile her, aber ich meine auch in C++ kann man nur virtuelle Methoden überschreiben.

Zitat:

Zitat von trebor90 (Beitrag 1152592)
Problem aber immer noch:
Was ist der Unterschied zwischen Verdecken und Ueberschreiben??
Ich kenne sowas wie "Verdecken" gar nicht.

Ich meine Verdecken ist das:
Delphi-Quellcode:
  TTestA= class
    procedure Test;
  end;

  TTestB= class(TTestA)
    procedure Test(A:Integer);
  end;
Das Test von TTestB verdeckt das Test von TTestA. Sprich folgendes lässt sich nicht kompilieren:
Delphi-Quellcode:
  ...
  B: TTestB
  ...
  B.Test;
  ...
Die Fehlermeldung wäre:
Code:
[DCC Fehler] MethodTracerUnit1.pas(119): E2035 Nicht genügend wirkliche Parameter
einbeliebigername.

MGC 24. Feb 2012 11:36

AW: Meine Probleme mit Delphi-OOP ...
 
Zitat:

Zitat von MGC (Beitrag 1152578)
In wie weit man hinter den ersten Konstruktor allerding override und overload zugleich setzen kann, weiß ich jetzt aus dem Stehgreif auch nicht, werde ich aber mal testen.

Ich zitiere mich hier mal selbst. Ich habe bereits im Thread mitgeteilt, dass ich mir nicht sicher bin ob es mit override und overload funktioniert. Hab ees jetzt getestet und bin in der Tat zu dem Schluss gekommen, dass man reintroduce verwenden muss, um überladene Methoden einzusetzen.

Was ich aber dennoch nicht ganz verstehe, weshalb eine feste Definition innerhalb einer Sprache nicht einfach hingenommen werden kann. Es gibt ja auch noch die Unterschiede bei div zwischen C++ und Delphi, wobei ich in dieser Hinsicht sagen muss, dass mir Delphi da besser gefällt. Auch dass es bei Delphi in der Grundeinstellung keine Header-Dateien gibt wie in C++ wurd enicht bemängelt, obwohl man dann von ganz unten bis nach ganz oben scrollen mus, anstatt einfach in den Header zu sehen wenn man Variablen oder Deklarartionen nochmals bearbeiten möchte.

himitsu 24. Feb 2012 12:44

AW: Meine Probleme mit Delphi-OOP ...
 
overload = überladen
override = überschreiben

überladen = gleichzeitig mehrere Methoden mit gleichem Namen, bzw. alte aus Vorfahren Methode nicht verdecken. (absichtliches Verdecken wird mit reintroduce angeben)
überschreiben = virtuelle (virtual) oder dynamische (dynamic) Methode des Vorfahren überschreiben, also den Eintrag in der VMT ändern.


scrollen ... dafür ibt es Listen und Tastenkürzel, im schnell hin- und herzuspringen, wie z.B. Strg+Shift+Hoch oder +Runter

MGC 24. Feb 2012 16:18

AW: Meine Probleme mit Delphi-OOP ...
 
@himitsu: Ist dies eine allgemeingültige Definition und somit auch auf Delphi übertragbar? Ich wäre jetzt sehr dankbar, wenn Du mir erklären würdest, warum der Delphi-Compiler dies anscheinend anders sieht.

Abgesehen davon, wenn man mit reintroduce absichtlich eine Methode überdeckt, aber mit inherited dafür sorgt, dass die originale Methode dennoch ausgeführt wird, was soll daran so schlimm sein?
Ich verstehe eben nach wie vor nicht, wen es gewisse Regeln zu geben scheint, an die man sich einfach zu halten hat, warum es so schwer ist genau dies zu tun?

Ich möchte hier niemandem mit dem Finger drohen, wie es anscheinend rüberkommt. Denke aber immer daran, dass die ursprüngliche Definition der OOP zugunsten der Praktikabilität nicht vollkommen umgesetzt wurde (z.B. bei der Polymorphie).

Zitat:

Aus Wikipedia - Prinzipien Objektorientiertes Design (Liskovsches Substitutionsprinzip)
[...]Damit ist garantiert, dass Operationen vom Typ Superklasse, die auf ein Objekt des Typs Subklasse angewendet werden, auch korrekt ausgeführt werden. Dann lässt sich stets bedenkenlos ein Objekt vom Typ Superklasse durch ein Objekt vom Typ Subklasse ersetzen. Objektorientierte Programmiersprachen können eine Verletzung dieses Prinzips, das aufgrund der mit der Vererbung verbundenen Polymorphie auftreten kann, nicht von vornherein ausschließen. Häufig ist eine Verletzung des Prinzips nicht auf den ersten Blick offensichtlich.[...]

himitsu 24. Feb 2012 16:26

AW: Meine Probleme mit Delphi-OOP ...
 
Wegen den anderen fragen schau ich dann nochmal nach.

Aber reintroduce schaltet eigentlich nur die Compilerwarnung ab.

Wenn man eine Methode verdeckt, dann wird man vom Compiler gewarnt. Und hat man absichtlich verdeckt, dann kann man das über reintroduce auch so markieren und weg ist die Warnung.



Ob die verdeckte Methode intern dann via inherited oder sonstwie aufberufen wird, ist dabei unwichtig.
Das Verdecken bezieht sich nur auf die äußere Schnittstelle, also das Interface (Deklaration) und nicht die Implementation (Code).

MGC 24. Feb 2012 16:40

AW: Meine Probleme mit Delphi-OOP ...
 
@himitsu: Besten Dank, wird notiert. Vielleicht nehme ich auch viel zu viel einfach als gegeben hin.

himitsu 24. Feb 2012 19:51

AW: Meine Probleme mit Delphi-OOP ...
 
Zitat:

Ist dies eine allgemeingültige Definition und somit auch auf Delphi übertragbar?
Ob es allgemeingültig ist, weiß ich nicht, was ich würde mal blind "ja" denken.
Overload, Override ist zumindestens in Delphi/Pascal so umgesetzt.


Virtual und Override ist so:

Gibt man in einer Klasse virtual für eine Methode an, dann wird dafür, in/ab diesem Typ ein Eintrag in der VMT angelegt.
Wenn man jetzt eine Variable mit diesem Typ anlegt, dann kennt dieser Typ seine VMT.

Nun könnte man in einer Variable auch einen Nachfahren dieses Typen abspeichern.

Ist in dem abgeleiteten Typen diese Methode überschrieben, dann wird das in der VMT vermerkt.
Damit kennt dann auch der Vorfahr den Zeiger zur neuen Methode, da es ja in der VMT drinsteht.

Wurde diese Methode aber nur verdeckt (egal ob sie Virtual ist oder nicht), dann kennt der Vorfahr diesen Zeiger nicht und kann damit immer nur seine Methode aufrufen.

Aus diesem Grund sind alle VCL-Komponenten von TComponent abgeleitet, wo vorallem der Constructor virtuell ist,
sowie bei allen Klassen der Destructor virtual ist.

Auf diese Weise kann die VCL den richtigen Constructor laden und auch immer der richtige Destructor ausgeführt werden, da der Vorfahre diese kennt.

MGC 24. Feb 2012 22:20

AW: Meine Probleme mit Delphi-OOP ...
 
Zitat:

Zitat von himitsu (Beitrag 1152743)
Aus diesem Grund sind alle VCL-Komponenten von TComponent abgeleitet, wo vorallem der Constructor virtuell ist,
sowie bei allen Klassen der Destructor virtual ist.

Auf diese Weise kann die VCL den richtigen Constructor laden und auch immer der richtige Destructor ausgeführt werden, da der Vorfahre diese kennt.

Stimmt, die Sache mit dem Eintrag in die VMT hatte ich vergessen. Daher muss ich ab diesem Punkt tatsächlich trebor90 rechtgeben. Die Handhabe von Delphi in bezug auf überladene Methoden, wenn die Hauptmethode im Basistyp als virtuell deklariert wurde, steht tatsächlich im Widerspruch zur OOP.

Verdecke ich ich einfach die original Methode, dann wird hier kein Eintrag in der VMT hinterlegt und ich muss sehr genau wissen ab welcher Stufe der Vererbung die entsprechende Methode mit reintroduce verdeckt wurde.

Wie verhält es sich nun bei Weiterveerbung? Sidn die Subklassen dann in der VMT ab hier auf die verdeckte Methode des Vorfahr bezogen oder wieder aufgrund der VMT auf die Superklasse?

Ich habe tatsächlich sehr viel dazugelernt. Bisher hätte ich nicht erwartet, dass Delphi sich im Gegensatz zu anderen OOP-Sprachen doch so entscheidende Abweichungen erlaubt.

Darüber hinaus habe ich auch mal Experimente mit der Mainform angestellt, weil ich jetzt wirklich wissen wollte, ob die globale Variable für das MainForm überflüssig ist.
Und uups, in der Tat es ist so, wenn ich das Fensterhandle des MainForms auslesen will, muss ich Application.Handle verwenden und tatsächlich nicht MainForm.Handle.

Vielen Dank für diesen Augenöffner.

himitsu 24. Feb 2012 22:29

AW: Meine Probleme mit Delphi-OOP ...
 
Mit der neuen RTTI könnte man zwar theoretisch auf auf die VMT und virtuelle Methoden verzichten, da man ja die Funktionen alle suchen und über die RTTI aufrufen könnte. (solange man die neue RTTI nicht einschränkt/abschaltet)
Bzw. über Published-Methoden der alten RTTI ginge es auch schon.

Aber schneller ist es über die VMT, denn ein indizierter Zugriff und man hat die aktuelle Methode.

Nachteil über die RTTI: Man könnte Methoden nicht verdecken, da sie dann ja automatisch überschrieben würden, wenn man ausnahmslos das Aktuellste sucht.
Und Klassenmethoden über eine Objektinstanz aufgerufen wären vermutlich nicht überschreibbar.

Robotiker 25. Feb 2012 08:34

AW: Meine Probleme mit Delphi-OOP ...
 
Übrigens hat man im neuen C++ Standard ein (optionales) override eingeführt, weil die bisherige Methode zu sehr subtilen Fehlern führen kann.

http://en.wikipedia.org/wiki/C%2B%2B...ides_and_final


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