Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Virtuelle Methode überladen (https://www.delphipraxis.net/181296-virtuelle-methode-ueberladen.html)

Nersgatt 4. Aug 2014 07:21

Virtuelle Methode überladen
 
Moin,

ich habe folgendes Konstrukt:
Delphi-Quellcode:
  TClass1 = class
  public
    procedure DoSomething; virtual;
  end;

  TClass2 = class(TClass1)
  public
    procedure DoSomething(AText : String); overload;
  end;
Beim Compilieren bekomme ich die Warnung: [dcc32 Warnung] Unit7.pas(17): W1010 Methode 'DoSomething' verbirgt virtuelle Methode vom Basistyp 'TClass1'

Ich verstehe nicht, warum das so ist. Die Deklaration von TClass2.DoSomething unterscheidet sich doch von TClass1.DoSomething (es wird ja nur eine Überladung hinzugefügt). Warum wird dann die Methode aus TClass1 verborgen? Und wie kann ich das verhindern?

Danke!

bepe 4. Aug 2014 07:37

AW: Virtuelle Methode überladen
 
Überladen wird innerhalb einer Klasse:

Delphi-Quellcode:
  TClass1 = class
   public
     procedure DoSomething; virtual; overload
     procedure DoSomething(AText : String); overload;
   end;
Möchtest du die Signatur in einer erbenden Klasse ändern musst du reintroduce benutzen:

Delphi-Quellcode:
  TClass1 = class
   public
     procedure DoSomething; virtual;
   end;

   TClass2 = class(TClass1)
   public
     procedure DoSomething(AText : String); reintroduce; // hier wird die Signatur nur geändert aber keine zweite Variante eingeführt
     procedure DoSomething(AText : String); reintroduce; overload // Hier wird eine zweite Variante definiert; entspricht overload innerhalb einer Klasse
   end;

Dejan Vu 4. Aug 2014 07:41

AW: Virtuelle Methode überladen
 
Zitat:

Zitat von Nersgatt (Beitrag 1267417)
Ich verstehe nicht, warum das so ist. Die Deklaration von TClass2.DoSomething unterscheidet sich doch von TClass1.DoSomething (es wird ja nur eine Überladung hinzugefügt). Warum wird dann die Methode aus TClass1 verborgen? Und wie kann ich das verhindern?

Rein theoretisch würde ich das auch nicht verstehen, aber in der Praxis musst Du die überladene Methode auch in der Grundklasse deklarieren.

Wenn das keine rein theoretische Frage ist, dann könnte das ein Hinweis auf ein schlechtes Design sein. Meistens findet man ein 'Workaround', d.h. eine Umformulierung des Codes, der sich im Nachhinein als sauberer herausstellt. Wieso z.B. muss die neue Methode genauso heißen? Macht sie wirklich das Gleiche?

@bepe: Ist dann in TClass2 auch 'DoSomething()' bekannt?

samso 4. Aug 2014 07:46

AW: Virtuelle Methode überladen
 
Falls Du DoSomething nur zusätzlich mit einem Parameter versehen willst, braucht sie nicht virtuell zu sein:

Delphi-Quellcode:
  TClass1 = class
  public
    procedure DoSomething; overload;
  end;

  TClass2 = class(TClass1)
  public
    procedure DoSomething(AText : String); overload;
  end;
Falls Du später auch noch überladen willst, ist das so möglich:

Delphi-Quellcode:
  TClass1 = class
  public
    procedure DoSomething; overload; virtual;
  end;

  TClass2 = class(TClass1)
  public
    procedure DoSomething(AText : String); overload;
  end;

Nersgatt 4. Aug 2014 07:57

AW: Virtuelle Methode überladen
 
Vielen Dank für die Erklärung. Mit reintroduce funktioniert es wie gewünscht. Damit wäre meine Frage erledigt.

Jetzt kommt der philosophische Teil, wo über den besten Weg diskutiert werden darf :D
Zitat:

Zitat von Dejan Vu (Beitrag 1267420)
Wenn das keine rein theoretische Frage ist, dann könnte das ein Hinweis auf ein schlechtes Design sein. Meistens findet man ein 'Workaround', d.h. eine Umformulierung des Codes, der sich im Nachhinein als sauberer herausstellt. Wieso z.B. muss die neue Methode genauso heißen? Macht sie wirklich das Gleiche?

Sie macht das Gleiche und noch ein bisschen mehr.

Ich könnte sie auch umbenennen, wobei ich mich frage, ob das in diesem Fall sauberer wäre.

Hier der "echte" Fall: es geht um die UniDac-Komponenten. Dazu gibt es den Sql-Monitor, der alle Sql-Anfragen, die von den Komponenten Richtung Server geschickt werden, ausgibt. Das ist sehr praktisch für Debuggingzwecke.
Die Connection bietet die Methode "MonitorMessage", mit der ich eine eigene Meldung im Sql-Monitor ausgeben kann (auch zu Debugzwecken manchmal hilfreich).

Die wollte ich nun mit dem Transactionhandling verbinden:
Delphi-Quellcode:
  TmyConnection = class(TUniConnection)
  private
    { Private-Deklarationen }
  protected
    { Protected-Deklarationen }
  public
    procedure StartTransaction(ASqlMonitorMessage : String); overload;
    procedure Commit (ASqlMonitorMessage : String); reintroduce; overload;
    procedure Rollback (ASqlMonitorMessage : String); reintroduce; overload;
  published
    { Published-Deklarationen }
  end;
Was dann entsprechend so implementiert ist:
Delphi-Quellcode:
procedure TmyConnection.Commit(ASqlMonitorMessage: String);
begin
  MonitorMessage('<< Committing Transaction: ' + ASqlMonitorMessage);
  Commit;
end;

procedure TmyConnection.Rollback(ASqlMonitorMessage: String);
begin
  MonitorMessage('!! Rolling back Transaction: ' + ASqlMonitorMessage);
  Rollback;
end;

procedure TmyConnection.StartTransaction(ASqlMonitorMessage: String);
begin
  MonitorMessage('>> Starting Transaction: ' + ASqlMonitorMessage);
  inherited StartTransaction;
end;
nun kann ich in TmyConnection.StartTransaction/Commit/Rollback einen eigenen Text mitgeben, der für die Fehlersuche (insbesondere beim Kunden, wo ich kein Delphi installiert hab) hilfreich sein soll.

Ich hätte natürlich auch die Methoden "StartTransactionWithMessage" oder so nennen können. Aber wäre das hier sinnvoll/sauber? :gruebel:
Ist sicher Ansichtssache.

Nersgatt 4. Aug 2014 07:58

AW: Virtuelle Methode überladen
 
Zitat:

Zitat von samso (Beitrag 1267421)
Falls Du DoSomething nur zusätzlich mit einem Parameter versehen willst, braucht sie nicht virtuell zu sein:

Das hat sich jetzt leider überschnitten. Wie Du an meinem vorherigen Post siehst, stammt TClass1 von einer Fremdkomponente. Daher ist die hier als gegeben anzusehen.

jaenicke 4. Aug 2014 11:01

AW: Virtuelle Methode überladen
 
Liste der Anhänge anzeigen (Anzahl: 1)
Nur so nebenbei, weil ich es in deinem Quelltext sehe:
Bei Interfaces und Strings macht es auf jeden Fall Sinn grundsätzlich bei Parametern const zu übergeben, da ansonsten dort jedesmal die Referenzzählung anspringt. Das ist zwar performancemäßig nicht spürbar, wenn solche Methoden nicht sehr oft aufgerufen werden, ist aber dennoch unnötig.
Den Unterschied siehst du im Anhang, so klein ist er nicht...

Dejan Vu 4. Aug 2014 13:23

AW: Virtuelle Methode überladen
 
Zitat:

Zitat von Nersgatt (Beitrag 1267422)
Aber wäre das hier sinnvoll/sauber? :gruebel:
Ist sicher Ansichtssache.

Der Designfehler liegt dann nicht bei Dir. Hier würde ich aber eine Wrapperklasse implementieren, die die TUniConnection intern verwendet. Der kannst Du dann deine eigene saubere Schnittstelle verpassen, mit overload etc.

Note: Overload finde ich fast immer Blödsinn. Ich würde hier nur eine Methode à la
Delphi-Quellcode:
Procedure Commit (const aSQLMessage : String = "");
anbieten. Aber auch das ist Ansichtssache.


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