Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Funktion Überladen --> Doppeldeutiger überladener Aufruf (https://www.delphipraxis.net/103482-funktion-ueberladen-doppeldeutiger-ueberladener-aufruf.html)

Ares 16. Nov 2007 11:34


Funktion Überladen --> Doppeldeutiger überladener Aufruf
 
Hallo!

Ich will eine Funktion GetString(ID: Integer) schreiben, die mir aus einer Liste einen bestimmten String liefert. Optional soll es zwei weitere Möglichkeiten geben:
1. String-Formatierung mit der Format() Funktion
2. String-Formatierung mit bestimmten, selbstdefinierten Optionen

Für diese Möglichkeiten habe ich die Funktion wie folgt überladen:

Delphi-Quellcode:
type
  TStringOption = (soQuoted, soBlank, soColon);
  TStringOptions = set of TStringOption;

function GetString(ID: Integer; StringOptions: TStringOptions=[]): String; overload;
function GetString(ID: Integer; Args: array of TVarRec): String; overload;
function GetString(ID: Integer; StringOptions: TStringOptions;
  Args: array of TVarRec): String; overload;

implementation

function GetString(ID: Integer; StringOptions: TStringOptions=[]): String;
begin
  result := GetString(ID, StringOptions, []);
end;

function GetString(ID: Integer; Args: array of TVarRec): String;
var dummy: TStringOptions;
begin
  dummy := [];
  result := GetString(ID, dummy, Args);
end;

function GetString(ID: Integer; StringOptions: TStringOptions;
  Args: array of TVarRec): String;
begin
  result := IrgendwieStringHolen(ID);
 
  Format(result, Args);

  if (soColon in StringOptions) then result := result+':';
  if (soBlank in StringOptions) then result := result+' ';
  if (soQuoted in StringOptions) then result := '"'+result+'"';
end;
Mit dieser Definition sollten eigentlich folgende Aufrufe der Funktion möglich sein:
Delphi-Quellcode:
GetString(123);             // Unformatierten String erhalten
GetString(123, [soQuoted]); // String mit ".." erhalten
GetString(123, ['hallo']);  // String erhalten bei dem ein %s durch "hallo" ersetzt ist

// String mit ".." erhalten und bei dem ein %s durch "hallo" ersetzt ist
GetString(123, [soQuoted], ['hallo']);
Auf den Aufrufen von 2 und 3 erhalte ich jedoch die Meldung Doppeldeutiger überladener Aufruf von 'GetString'. Eigentlich sollte Delphi doch durch den Typ der Parameter bestimmen können, welche Funktion genutzt werden soll. Einmal ist der zweite Parameter eindeutig ein Array und einmal eindeutig eine Menge. Wo ist also das Problem?

Ich habe schon versucht die Defaultbelegung TStringOptions=[] wegzulassen und stattdessen eine weitere überladene Version der Funktion zu nutzen. Das Ergebnis ist das Gleiche.

Die Funktion GetString zusammen mit dem TVarRec nutze ich schon an sehr vielen Stellen in meinen Programmen. Ich wollte nun nur zusätlich die eigenen Optionen einfügen, ohne dass die vorhandenen Aufrufe von GetString geändert werden müssen.

Was mache ich also falsch und wie lässt sich das Problem umgehen?

Natürlich könnte ich nur eine Version der Funktion benutzen bei der alle Parameter angegeben werden müssen. Aber zum einen sollte das Überladen von Funktionen doch kein Problem sein und zum anderen müsste ich dann die vielen vorhandenen Aufrufe von GetString ändern. Das will ich möglichst vermeiden.

Besten Dank
Ares



Dazu soll es noch die Möglichkeit geben der Funktion Argument für die String-Formatierung und

messie 16. Nov 2007 14:27

Re: Funktion Überladen --> Doppeldeutiger überladener Auf
 
Zitat:

Zitat von OH
If you use default parameter values in an overloaded routine, avoid ambiguous parameter signatures. Consider, for example, the following.

Delphi-Quellcode:
procedure Confused(I: Integer); overload;

 ...
procedure Confused(I: Integer; J: Integer = 0); overload;
 ...
Confused(X);   //  Which procedure is called?
In fact, neither procedure is called. This code generates a compilation error.

Die Parametersätze in den unterschiedlichen Deklarationen dürfen nicht übereinstimmen, was in Deinem Fall aber mehrfach so ist. Das ist mit der Doppeldeutigkeit gemeint.

Grüße, Messie

himitsu 16. Nov 2007 14:34

Re: Funktion Überladen --> Doppeldeutiger überladener Auf
 
@messie:
tun sie doch auch nicht.

Delphi-Quellcode:
// das
ID: Integer; StringOptions: TStringOptions=[];
// enspricht dem und soeinen Parametersatz gibt es noch nicht
ID: Integer;
und die beiden anderen Parametersätze sind
Delphi-Quellcode:
ID: Integer; Args: array of TVarRec
ID: Integer; StringOptions: TStringOptions; Args: array of TVarRec
also meiner Meinung nach sollte es eigentlich gehn :gruebel:
Code:
Integer; [color=#a0a0a0]TStringOptions[/color]
Integer; array_of_TVarRec
Integer; TStringOptions; array_of_TVarRec

messie 16. Nov 2007 15:03

Re: Funktion Überladen --> Doppeldeutiger überladener Auf
 
Aber das erste Argument ist immer ein integer. Das entspricht genau dem, was die OH als abschreckendes Beispiel genannt hat. Woher soll die Funktion wissen, wieviel Speicherplätze mit welcher Speicherstruktur sie beim Aufruf für die Parameter reservieren soll?

Grüße, Messie

RavenIV 16. Nov 2007 15:17

Re: Funktion Überladen --> Doppeldeutiger überladener Auf
 
Zitat:

Zitat von himitsu

Delphi-Quellcode:
function GetString(ID: Integer; StringOptions: TStringOptions=[]): String; overload;
function GetString(ID: Integer; Args: array of TVarRec): String; overload;
function GetString(ID: Integer; StringOptions: TStringOptions;
  Args: array of TVarRec): String; overload;

Das funktioniert so auch nicht.
Wenn Du bei der dritten Schreibweise den zweiten und dritten Parameter vertauschst, dann könnte es klappen.

himitsu 16. Nov 2007 15:27

Re: Funktion Überladen --> Doppeldeutiger überladener Auf
 
Nein, die OH schrieb von

Code:
procedure Confused([color=red]Integer[/color]);
procedure Confused([color=red]Integer[/color]; [color=silver]Integer=0[/color]);
fällt dir was auf?

die zweite Prozedur endspricht genau der Ersten, wenn man den optionalen Parameter wegläßt.

Dax 16. Nov 2007 15:31

Re: Funktion Überladen --> Doppeldeutiger überladener Auf
 
Delphi-Quellcode:
function GetString(ID: Integer; StringOptions: TStringOptions=[]): String; overload;
function GetString(ID: Integer; Args: array of TVarRec): String; overload;
function GetString(ID: Integer; StringOptions: TStringOptions;
  Args: array of TVarRec): String; overload;
Was stellt [] bei GetString(0, []) nun dar? Ein leeres Set oder ein leeres Array?

DeddyH 16. Nov 2007 15:41

Re: Funktion Überladen --> Doppeldeutiger überladener Auf
 
IMHO sollte es so ohne Probleme gehen:
Delphi-Quellcode:
function GetString(ID: Integer; StringOptions: TStringOptions=[]): String; overload;
function GetString(Args: array of TVarRec; ID: Integer): String; overload; //Argumente getauscht
function GetString(ID: Integer; StringOptions: TStringOptions;
  Args: array of TVarRec): String; overload;
Falls nicht, möge man mich korrigieren.

messie 16. Nov 2007 22:23

Re: Funktion Überladen --> Doppeldeutiger überladener Auf
 
So ähnlich hatte ich das auch schon probiert - also jedesmal ein neuer einleitender Parameter. Gescheitert ist der Compiler daran, daß er laut #1 eine jeweils andere Variante "von sich selbst" aufrufen sollte. Da scheint sogar die Reihenfolge der Deklarationen Einfluss zu haben.
Ein interessantes Thema...

Grüße, Messie

Dax 16. Nov 2007 22:25

Re: Funktion Überladen --> Doppeldeutiger überladener Auf
 
Delphi-Quellcode:
function GetString(ID: Integer; StringOptions: TStringOptions=[]): String; overload;
function GetString(ID: Integer; Args: array of TVarRec; StringOptions: TStringOptions = []): String; overload;
Geht das denn so?

messie 16. Nov 2007 22:28

Re: Funktion Überladen --> Doppeldeutiger überladener Auf
 
[OT] heute nicht mehr...[/OT]
Aber die Deklarationen sollten mal ohne die gegenseitigen Aufrufe probiert werden. Vielleicht läßt sich das damit etwas entflechten.

Grüße, Messie

Ares 19. Nov 2007 09:13

Re: Funktion Überladen --> Doppeldeutiger überladener Auf
 
Hallo!

Vielen Dank für eure zahlreichen Beiträge. Ich hatte am Wochenende leider keine Gelegenheit zu antworten.

Code:
procedure Confused([color=red]Integer[/color]);
procedure Confused([color=red]Integer[/color]; [color=silver]Integer=0[/color]);
Das dies zu Problem führt verstehe ich. Bei einem Aufruf von Confuses(42) weiß der Compiler nicht, ob er die erste Variante aufrufen soll, oder die zweite Variante mit der Defaultbelegung für den zweiten Paramter (Confuses(42, 0)). Dieses Problem tritt bei meinen Funktionen aber eigentlich nicht auf. Hier sollte anhand der Paramter immer ganz eindeutig klar sein, welche Funktion genutzt werden soll.

Um das Problem mit dem Default Paramter zu umgehen, habe ich noch eine weitere Funktion eingführt:
Delphi-Quellcode:
{#1} function GetString(ID: Integer): String; overload;
{#2} function GetString(ID: Integer; StringOptions: TStringOptions): String; overload;
{#3} function GetString(ID: Integer; Args: array of TVarRec): String; overload;
{#4} function GetString(ID: Integer; StringOptions: TStringOptions;
       Args: array of TVarRec): String; overload;
Wenn ich das Ganz nun mit folgenden Aufrufen teste, erhalte ich bei den 2, 3 und 4 die Meldung mit der doppeldeutigen Überladung:
Delphi-Quellcode:
// 1. Parameter (Integer) --> Funktion #1
str := GetString(42);

// 2. Parameter (Integer, TStringOptions) --> Funktion #2
str := GetString(42, [soQuoted]);

// 3. Parameter (Integer, TVarRec) --> Funktion #3
str := GetString(42, ['hallo']);

// 4. Parameter (Integer, TStringOptions, TVarRec) --> Funktion #4
str := GetString(42, [soQuoted], ['hallo']);
Soweit ich das verstehe ich eigentlich in jeder Situation durch die Parameter ganz eindeutig bestimmt, welche Funtkion genutzt werden soll.

Zitat:

Zitat von messie
Aber das erste Argument ist immer ein integer. Das entspricht genau dem, was die OH als abschreckendes Beispiel genannt hat. Woher soll die Funktion wissen, wieviel Speicherplätze mit welcher Speicherstruktur sie beim Aufruf für die Parameter reservieren soll?

So wie bei jeder anderen überladenen Funktion auch: Durch die Zahl und den Typ der übrigen Paramter. Ich dachte eigentlich immer, dass sollte so funktionieren. Folgendes funktioniert prima obwohl der erste Parameter immer Integer ist:
Delphi-Quellcode:
function OverloadTest(ID: Integer): String; overload;
function OverloadTest(ID: Integer; Str: String): String; overload;
..
OverloadTest(42);
OverloadTest(42, 'hallo');

Zitat:

Zitat von RavenIV
Wenn Du bei der dritten Schreibweise den zweiten und dritten Parameter vertauschst, dann könnte es klappen.

Das änder leider nichts. Die Fehler treten ganz genauso auf.


Zitat:

Zitat von messie
Aber die Deklarationen sollten mal ohne die gegenseitigen Aufrufe probiert werden. Vielleicht läßt sich das damit etwas entflechten.

Das Spielt keine Rolle. Dann tritt der Fehler auf, wenn man die Funktion im sonstigen Programm verwendet.


Zitat:

Zitat von DeddyH
IMHO sollte es so ohne Probleme gehen:
Delphi-Quellcode:
function GetString(ID: Integer; StringOptions: TStringOptions=[]): String; overload;
function GetString(Args: array of TVarRec; ID: Integer): String; overload; //Argumente getauscht
function GetString(ID: Integer; StringOptions: TStringOptions;
  Args: array of TVarRec): String; overload;
Falls nicht, möge man mich korrigieren.

Das funktioniert wirklich. Allerdings habe ich dann das Problem, dass ich alle Stelle an denen GetString(Integer; array of TVarRec) vorkommt ändern muss. Und das sind ziemlich viele.

Falls es gar nicht anders geht werde ich es also so machen. Wenn aber noch jemand eine Idee für eine elegantere Lösung hat wäre ich dafür wirklich dankbar!

Besten Dank
Ares

Schwedenbitter 3. Feb 2010 12:44

Re: Funktion Überladen --> Doppeldeutiger überladener Auf
 
Hallo,

ich wollte wegen meiner Frage kein neues Them aufmachen. Vielleicht kann mir ja hier schon jemand sagen, warum ich bei folgendem die besagte Fehlermeldung bekomme:
Delphi-Quellcode:
Function ExpandAz(Var Value: String): String; Overload;
Function ExpandAz(Value: TCaption): String; Overload;
...

// -----------------------------------------------------------
// Erweitert ein Aktenzeichen, bei dem führende Nullen oder
// die führenden "19" oder "20" bei der Jahreszahl weggelassen
// wurden
Function ExpandAz(Var Value: String): String;
Var
  S            : String;
  I            : Integer;
Begin
  Result:='';
  If Value <> '' Then
  Begin
    S:=SepString(Value, '/');          // Aktenzeichen und Jahr trennen
    If TryStrToInt(S, I) Then          // numerisches Aktenzeichen ?
      S:=FormatFloat('0000', I);       // mit führenden Nullen
    If TryStrToInt(Value, I) Then
    Begin
      If I < 1999 Then Inc(I, 2000);   // ggf. Dekaden ergänzen (1900er egal)
        S:=IntToStr(I);                // kompl. Jahr in Str. umwandeln
      Result:=S + '/' + Value;         // Az. und Jahr wieder zusammensetzen
    End;
  End;
End;
Function ExpandAz(Value: TCaption): String;
Var
  S            : String;
Begin
  S:=Value;                            // auf String übertragen
  Result:=ExpandAz(S);   
End;
Mein Ziel - falls ich es auch anders erreichen kann - ist es, die Function auch mit TEdit.Text vom Typ TCaption als Parameter aufrufen zu können.

Danke und Gruß, Alex

DeddyH 3. Feb 2010 12:48

Re: Funktion Überladen --> Doppeldeutiger überladener Auf
 
Zitat:

Delphi-Quellcode:
type
  TCaption = type string;

Ist also auch nichts anderes und somit für den Compiler nicht unterscheidbar.

Schwedenbitter 3. Feb 2010 15:15

Re: Funktion Überladen --> Doppeldeutiger überladener Auf
 
Zitat:

Zitat von DeddyH
Ist also auch nichts anderes und somit für den Compiler nicht unterscheidbar.

Ich habe das Problem jetzt anders gelöst. Bei mir (TurboDelphi) ist TCaption übrigens ein AnsiString. Den habe ich für die Function genommen und der Compiler akzeptiert dann auch einen "normalen" String. Vorteil: Nur noch eine Function ohne zu überladen etc.
Es stellt sich mir aber die Frage, warum ich dann eine Fehlermeldung bekomme. Denn wenn TCaption = String ist, dann müsste das auch der Compiler wissen (:lol:) und es wäre keine Fehlermeldung zu erwarten.

Gruß und Danke, Alex

himitsu 3. Feb 2010 15:53

Re: Funktion Überladen --> Doppeldeutiger überladener Auf
 
Der String ist in TDE eine Weiterleitung zum AnsiString.


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