2013-10-05 11 views
20

Im folgenden Code, Funktionszeiger und was ich als als „Funktionsverweis“ scheint identisch Semantik zu haben:Funktionszeiger vs Funktionsreferenz

#include <iostream> 
using std::cout; 

void func(int a) { 
    cout << "Hello" << a << '\n'; 
} 
void func2(int a) { 
    cout << "Hi" << a << '\n'; 
} 

int main() { 
    void (& f_ref)(int) = func; 
    void (* f_ptr)(int) = func; 

    // what i expected to be, and is, correct: 
    f_ref(1); 
    (*f_ptr)(2); 

    // what i expected to be, and is not, wrong: 
    (*f_ref)(4); // i even added more stars here like (****f_ref)(4) 
    f_ptr(3); // everything just works! 

    // all 4 statements above works just fine 

    // the only difference i found, as one would expect: 
// f_ref = func2; // ERROR: read-only reference 
    f_ptr = func2; // works fine! 
    f_ptr(5); 

    return 0; 
} 

ich gcc Version 4.7.2 in Fedora/Linux verwendet

UPDATE

Meine Fragen sind:

  1. Warum benötigt der Funktionszeiger keine Dereferenzierung?
  2. Warum führt die Dereferenzierung einer Funktionsreferenz nicht zu einem Fehler?
  3. Ist (gibt es) Situationen, in denen ich eine über die andere verwenden muss?
  4. Warum funktioniert f_ptr = &func;? Da Func in einen Zeiger zerfallen sollte?
    Während f_ptr = &&func; funktioniert nicht (implizite Konvertierung von void *)

Antwort

10

Funktionen und Funktionsreferenzen (dh id-Ausdrücke dieser Typen) Zerfall in Funktionszeiger fast sofort, so dass die Ausdrücke func und f_ref tatsächlich worden Funktionszeiger in Ihrem Fall. Sie können auch (***func)(5) und (******f_ref)(6) anrufen, wenn Sie möchten.

Es kann vorzuziehen sein, Funktionsreferenzen in Fällen zu verwenden, in denen der & -Operator so funktionieren soll, als wäre er auf die Funktion selbst angewendet worden, z. &func ist das gleiche wie &f_ref, aber &f_ptr ist etwas anderes.

+0

ist das ein Implementierungsfehler? "coz, das geht gegen unsere intuitiven Konzepte von" tippen ", nicht wahr? Ich habe auch etwas wie 'void (* & f) (void)' als Funktionsparameter gesehen - '*' und '&' zusammen benutzt .. wie kommt es? – John

+0

Es ist kein Fehler, nur die Art wie die Sprache definiert ist. In Ausdrücken gibt es grundsätzlich keine Funktionen, es gibt nur Funktionszeiger; Decay sorgt dafür, dass die "offensichtliche" Syntax funktioniert (d. h. Sie können 'f (1)' anstelle von "tumber" (& f) (1) ') eingeben. –

+0

@John: Vergleichen Sie mit der Art, wie Arrays gehandhabt werden; sie können nicht durch den Wert übergeben werden, so dass in einem Funktionsprototyp "int x []" (und zu diesem Zweck ("int x [10]") äquivalent zu "int * x" ist, da ein C-Array empfangen wird value ist nicht legal, sie lassen die Array-Deklarationssyntax als syntaktischen Zucker zum Empfangen eines Zeigers verwenden. – ShadowRanger

2

Siehe here.

Der Adressoperator verhält sich wie erwartet, da er auf eine Funktion verweist, aber nicht zugewiesen werden kann. Funktionen werden in Funktionszeiger umgewandelt, wenn sie als R-Werte verwendet werden, was bedeutet, dass Sie einen Funktionszeiger beliebig oft dereferenzieren und denselben Funktionszeiger zurückholen können.

9

"Warum Funktionszeiger benötigt keine Dereferenzierung?"

Da die Funktionskennung selbst ist tatsächlich ein Zeiger auf die Funktion bereits:

4,3 Function-to-Zeigerumwandlungs
§1 ein L-Wert von Funktionstyp T umgewandelt werden kann zu einem rvalue vom Typ "Zeiger auf T." Das Ergebnis ist ein Zeiger auf die Funktion.

„Warum eine Funktionsreferenz dereferencing führt nicht zu einem Fehler?“

Grundsätzlich können Sie die Definition einer Referenz als Definition eines Alias ​​(alternativer Name) betrachten.Auch in der Norm in 8.3.2 Referenzen teilweise Adressierung der Erstellung eines Verweises auf ein Objekt, finden Sie:
"eine Referenz kann als Name eines Objekts gedacht werden."

Also, wenn Sie definieren einen Verweis:

void (& f_ref)(int) = func; 

es Ihnen die Möglichkeit, f_ref gibt fast überall zu verwenden, wo es möglich wäre, func zu verwenden, was der Grund ist, warum:

f_ref(1); 
(*f_ref)(4); 

funktioniert genauso wie unter Verwendung der func direkt:

func(1); 
(*func)(4);