Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Halb-virtuelle Methoden (https://www.delphipraxis.net/183307-halb-virtuelle-methoden.html)

Der schöne Günther 30. Dez 2014 13:40

Delphi-Version: XE7

Halb-virtuelle Methoden
 
Ich bin zu ungeschickt, in den Weiten des Internets richtig danach zu suchen. Folgender Code:
Delphi-Quellcode:
program Project15; {$APPTYPE CONSOLE} {$R *.res}

uses System.SysUtils;

type
   IMyInterface = interface
      procedure interfaceProc();
   end;

   TMyBase = class(TInterfacedObject, IMyInterface)
      procedure interfaceProc();// virtual;
   end;

   TMyChild = class(TMyBase, IMyInterface)
      procedure interfaceProc();// override;
   end;

procedure TMyBase.interfaceProc();
begin
   WriteLn('TMyBase');
end;

procedure TMyChild.interfaceProc();
begin
   inherited;
   Writeln('TMyChild');
end;

var
   interfaceVariable: IMyInterface;
   classVariable: TMyBase;
begin
   WriteLn('interface variable');
   interfaceVariable := TMyChild.Create();
   interfaceVariable.interfaceProc();

   Write(sLineBreak);

   WriteLn('class type variable');
   classVariable := TMyChild.Create();
   classVariable.interfaceProc();

   readln;
end.
erzeugt die Ausgabe
Code:
interface variable
TMyBase
TMyChild

class type variable
TMyBase
Sprich: Spreche ich die Instanz mit einer Interface-Variable an wird die Methode behandelt, als hätte ich virtual angegeben. Nehme ich die Klassenreferenz wird sie nicht virtual behandelt.

Warum ist das so? Könnte folgendes etwas damit zu tun haben?
http://docwiki.embarcadero.com/RADSt...mplementations


Lange Rede kurzer Sinn: Sollte ich bei implementierten Interface-Methoden nun eine virtual-Direktive dahintersetzen? Eigentlich kann ich mir das ja dann sparen...

alda 30. Dez 2014 13:47

AW: Halb-virtuelle Methoden
 
Ist doch völlig logisch, der Aufruf über die variable "classVariable" hat rein garnichts mit dem Interface zu tun und sollte so auch nicht benutzt werden - also ja, hier bräuchtest Du ein virtual - oder übersehe ich hier etwas ?

Übrigens: der Aufruf von
Delphi-Quellcode:
...
classVariable.interfaceProc();
...
sollte in einer AV resultieren, da die Instanz aufgrund der fehlenden Referenz nach dem Create wieder den ReferenceCount 0 erhält.

Edit:
Jetzt sehe ich worauf Du hinaus willst, hatte die Ausgabe von "TMyBase" UND "TMyChild" beim ansprechen der "interfaceVariable" übersehen. Dieses Verhalten ist mir in der tat noch nicht aufgefallen, aber ich habe auch sehr selten solch eine Konstellation. Spontan würde ich die Klassen in der Tat so deklarieren, wie Du es angedeutet hast:
Delphi-Quellcode:
TMyBase = class(TInterfacedObject, IMyInterface)
   procedure interfaceProc(); virtual;
  end;

TMyChild = class(TMyBase)
   procedure interfaceProc(); override;
end;

Sir Rufo 30. Dez 2014 17:54

AW: Halb-virtuelle Methoden
 
Das sollte schon bekannt sein, dass bei
Delphi-Quellcode:
var
  LInstance : TMyBase;
begin
  LInstance := TMyChild.Create;
  LInstance.interfaceProc; // ruft TMyBase.interfaceProc auf!!!
end;
eben die Methode
Delphi-Quellcode:
TMyBase.interfaceProc
aufgerufen wird, aufgrund der Deklaration von
Delphi-Quellcode:
LInstance : TMyBase
.

Aus diesem Grund muss die Methode zwingend als
Delphi-Quellcode:
virtual
deklariert werden, dann wird die auch in der abgeleiteten und erzeugten Klasse gefunden.

Allerdings funktioniert dies hier
Delphi-Quellcode:
var
  LInstance : TMyChild;
begin
  LInstance := TMyChild.Create;
  LInstance.interfaceProc; // ruft TMyChild.interfaceProc auf!!!
end;
wie erwartet :)

Dejan Vu 30. Dez 2014 18:19

AW: Halb-virtuelle Methoden
 
Also in meinen Augen ist das mal wieder 'typisch halbausgegorener Delphi-Mist'.

Die 2. Deklaration (TMyChild implementiert IMyInterface) ist redundant, da es von TMyClass abgeleitet ist und diese ja schon das Interface implementiert. Weiterhin müsste die 'interfaceproc' Routine als virtual deklariert werden, da sie ja überschrieben wird.

Es muss doch egal sein, ob ich über das Interface oder die Klasse eine Implementierung aufrufe. So, wie das hier von Delphi umgesetzt wurde, ist das doch totaler Murks: Wir erlauben z.B. nur die Verwendung von Interfacevariablen, die Instantiierung erfolgt nur über eine Fabrik. Intern jedoch kann es durchaus sein, das eine Klasse direkt verwendet wird, um z.B. auf public Methoden zugreifen zu können, die nicht im Interface angegeben sind.

Grauslich.


Edit: Der obige Text ist -bis auf den Einwand mit der redundanten Angabe des Interfaces in der Deklaration von TMyChild- Quatsch. Ich lass ihn aber so. Begründung siehe folgende Beiträge

Der schöne Günther 30. Dez 2014 18:38

AW: Halb-virtuelle Methoden
 
Hoppla, stimmt:
Ändere
Delphi-Quellcode:
   TMyChild = class(TMyBase, IMyInterface)
      procedure interfaceProc();// override;
   end;
zu
Delphi-Quellcode:
   TMyChild = class(TMyBase)
      procedure interfaceProc();// override;
   end;
und erhalte plötzlich
Code:
interface variable
TMyBase

class type variable
TMyBase
Total komisch. :roteyes:


Trotzdem macht der Compiler die Methoden irgendiwe "halb-virtuell", denn wenn ich
Delphi-Quellcode:
classVariable
zu TMyChild caste, ruft
Delphi-Quellcode:
interfaceProc()
mittels
Delphi-Quellcode:
inherited
völlig gelassen die Methode der Oberklasse auf. Obwohl nie jemand gesagt hat, dass diese Methode virtuell sein soll.

Sir Rufo 30. Dez 2014 18:46

AW: Halb-virtuelle Methoden
 
Na dann versuch doch mal das hier:
Delphi-Quellcode:
var
  LBase : TMyBase;
  LChild : TMyChild;
begin
  LBase := nil;
  LChild := nil;

  LBase.interfaceProc;
  LChild.interfaceProc;
end;
Aha, jetzt wissen wir das auch ;)

Der schöne Günther 30. Dez 2014 19:04

AW: Halb-virtuelle Methoden
 
:wiejetzt:

Mein Punkt ist: Niemand schreibt irgendwo
Delphi-Quellcode:
virtual
. Trotzdem wird sie "halb virtuell" gemacht: Halb, da ich von der Unterklasse mittels
Delphi-Quellcode:
inherited
die Methode der Oberklasse aufrufen kann obwohl niemand irgendwo
Delphi-Quellcode:
override
sagt.

alda 30. Dez 2014 19:21

AW: Halb-virtuelle Methoden
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1285011)
:wiejetzt:

Mein Punkt ist: Niemand schreibt irgendwo
Delphi-Quellcode:
virtual
. Trotzdem wird sie "halb virtuell" gemacht: Halb, da ich von der Unterklasse mittels
Delphi-Quellcode:
inherited
die Methode der Oberklasse aufrufen kann obwohl niemand irgendwo
Delphi-Quellcode:
override
sagt.

Die Eigenschaft "virtual" sagt ja auch nur aus, dass man die Methode überschreiben darf. Das "inherited" ruft einfach die geerbte Methode auf, das hat ja erstmal nichts mit der Eigenschaft virtual zu tun.

Sir Rufo 30. Dez 2014 20:21

AW: Halb-virtuelle Methoden
 
Du kannst quasi jede Methode (private sind schwierig bis gar nicht zu erreichen) in einer Ableitung überschreiben, aber wenn die Methode nicht als
Delphi-Quellcode:
virtual
deklariert ist, dann bekommst du genau das Verhalten wie du es hier siehst/zeigst, ansonsten ist es so wie erwartet.

Ist eine Methode
Delphi-Quellcode:
virtual
, dann kann man sich mit Delphi-Referenz durchsuchenTVirtualMethodInterceptor in die Methodenaufrufe einklinken, bei allen anderen Methoden ist das nicht möglich. Das liegt an der Verwaltung der Klassenstruktur, die man mit genau diesem
Delphi-Quellcode:
virtual
festlegt.

Sir Rufo 30. Dez 2014 20:25

AW: Halb-virtuelle Methoden
 
Die Dokumentation ist da auch eindeutig

http://docwiki.embarcadero.com/RADSt...ethodenbindung


Alle Zeitangaben in WEZ +1. Es ist jetzt 15:55 Uhr.
Seite 1 von 2  1 2      

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