2016-06-03 5 views
4

Wird die folgende Arbeit wie erwartet ?:Ist es in C++ erlaubt, einen Funktionszeiger auf einen zu setzen, der als Parameter einen Zeiger auf eine Basis oder abgeleitete Klasse bekommt?

struct A {}; 

struct B: public A { 
    int x; 
    }; 

void f(B* o) { 
    std::cout << o->x << std::endl; 
    } 

int main() { 
    B b; 
    b.x = 5; 
    reinterpret_cast<void(*)(A*)>(f)(&b); 
    } 
+1

Wahrscheinlich hängt es von den Erwartungen ab ... – luk32

+1

Ist das nur akademische Neugier, oder gibt es ein praktisches Problem, das Sie zu lösen versuchen? –

+1

@RSahu: Es ist tatsächlich nützlich für mich geworden, aber ich bevorzuge es, das Beispiel so klein wie möglich zu halten. –

Antwort

5

Sein undefinierten Verhalten solcher Zeiger nach Guss verwenden:

Alle Zeiger auf Funktion kann auf einen Zeiger auf einen anderen Funktionstyp umgewandelt werden. Der Aufruf der Funktion durch einen Zeiger auf einen anderen Funktionstyp ist nicht definiert, aber die Umwandlung eines solchen Zeigers in den Zeiger auf den ursprünglichen Funktionstyp ergibt den Zeiger auf die ursprüngliche Funktion.

Von http://en.cppreference.com/w/cpp/language

So ist die Antwort auf Ihre Frage ist eigentlich positiv - Sie dürfen werfen, aber nichts mehr.

Sie könnten fragen: "Was ist der Sinn des Castings?" - Dies ist nützlich, wenn Sie verschiedene Funktionen in einer Sammlung speichern möchten.

5

Siehe 5.2.10/6 [expr.reinterpret.cast]:

Ein Funktionszeiger kann explizit in einen Funktionszeiger von einem anderen Typ umgewandelt werden. Der Aufruf einer Funktion durch einen Zeiger auf einen Funktionstyp, der nicht mit dem bei der Definition der Funktion verwendeten Typ übereinstimmt, ist nicht definiert.

Das heißt, Note als ein Beispiel, dass C++ Sie zu dereferenzieren einen Null-Zeiger ermöglicht, vielleicht erlaubt nicht der richtige Begriff ist. Auch
Der folgende Befehl erstellt:

reinterpret_cast<void(*)(A*, int)>(f)(&b, 42); 

Es ist erlaubt, sowie der in der Frage, egal ob es wie erwartet funktioniert oder nicht (es meist auf Ihren Erwartungen abhängt, wie bereits von @ luk32 in den Kommentaren).

Die Antwort auf Ihre Frage wäre ja, die Besetzung ist erlaubt, aber das Aufrufen der Funktion durch den neuen Zeiger führt zu einem undefinierten Verhalten.

+0

Warum überraschend? Undefiniert bedeutet, dass alles passieren kann, nicht dass es nicht kompiliert wird. Grundsätzlich geht alles, was "reinterpret_cast" beinhaltet, in die Schublade. Ich glaube, dass es auch für Typen ähnliche Aussagen gibt. – luk32

+0

Richtig, sogar _surprising_ ist nicht der richtige Ausdruck in der Tat. – skypjack

+0

Ich denke, "erlaubt" ist eigentlich eine gute Wortwahl hier. Der Subtext ist "ist ein wohlgeformtes C++ Programm erlaubt zu ...?". Eigentlich aus den Gründen, auf die Sie hinweisen, denke ich "erlaubt"! = "Passiert, um zu kompilieren" –