Zeiger auf überladene Funktionen

Wie bekommt man die Adresse einer überladenen Funktion? Bei mehreren überladenen Funktionen gleichen Namens (beispielsweise f) wird diejenige verwendet, deren Typ zur Verwendung von &f paßt. Demnach ist eine Verwendung, aus der der geforderte Typ nicht hervorgeht, unzulässig (wie void *p = &f; etwa).

#include <iostream>


int up( int a, int b )
{
 std::cout << "int-Version: a=" << a << ", b=" << b << std::endl;
 return 1;
}

int up( double a, double b )
{
 std::cout << "double-Version: a=" << a << ", b=" << b << std::endl;
 return 2;
}

int main( int nargs, char **args )
{

 int(*p)(int, int);

 // p hat den Typ "Zeiger auf Funktion, die zwei int bekommt, und
 // eine int liefert". Nur deshalb wird für &up die Adresse der
 // ersten up genommen.
 // Das ist eine eklatante Verletzung der von mir schon im Umlauf
 // gebrachten (eigentlich eisernen Regel), daß die Verwendung eines
 // Ausdrucks keinen Einfluß auf seine Auswertung hat (in C gilt
 // diese Regel auch uneingeschränkt!).
 // Es sollte also der Typ des Ausdrucks links einer Zuweisung
 // niemals einen Einfluß auf die Auswertung der rechten Seite haben;
 // hier ist es aber ausnahmsweise anders:
 p = &up;

 // Weil p (laut seiner Deklaration) auf eine Funktion zeigt, die
 // zwei int bekommt, wird beim Aufruf mit doubles implizit nach int
 // gecastet; es wird in beiden Fällen das erste up korrekt
 // aufgerufen:
 (*p)( 12, 13 );
 (*p)( 12.8, 13.9 );


 // Jetzt machen wir etwas Versautes!
 // Die Adresse von up wird jetzt mit einem cast zu einer
 // (int(*)( double, double )) gemacht. Dieser cast bewirkt
 // tatsächlich etwas, nämlich daß die Adresse der zweiten
 // up-Funktion genommen wird (die mit den double als Parameter).
 // Dieser cast beeinflußt also auf die Auswertung von &up.
 // Als
 //    p = (int(*)( double, double ))&up;
 // wäre die Zuweisung nicht zulässig (Compilerfehler, weil der Typ
 // der zugewiesen wird, nicht mit dem Typ der Variablen p
 // zusammenpaßt).
 // Das Ergebnis wird aber mit dem linken cast (int(*)( int, int ))
 // in einen "Zeiger auf Funktion, die zwei int bekommt und eine int
 // liefert" gecastet; die Zuweisung wird damit erzwungen.
 // Dieser cast bewirkt jetzt nur, daß der Compiler die Zuweisung
 // akzeptiert und hat sonst keine Auswirkung.
 p = (int(*)( int, int ))  (int(*)( double, double ))&up;


 // Jetzt steht in p die Adresse des zweiten up, einer
 // "Funktion, die zwei double bekommt und eine int liefert".
 // Der Compiler geht aber wegen der Deklaration von p davon aus, daß
 // p auf eine "Funktion, die zwei int bekommt und eine int
 // liefert" zeigt. Schade!
 std::cout << "Achtung, Schweinerei! Das geht schief!" << std::endl;
 // Die beiden Parameter werden als int an das zweite up übergeben,
 // und die Bitmuster der beiden int (und des dahinter liegenden
 // Speichers, wenn double mehr Bytes belegt als int!) als double
 // verwendet:
 (*p)( 12, 13 );
 // Analog: die beiden double werden implizit nach int gecastet, und
 // die Bitmuster der ints vom zweiten up als double verwendet:
 (*p)( 12.8, 13.9 );

 return 0;
} // main( int nargs, char **args )



AnyWare@Wachtler.de