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 )