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 )