2015-02-07 4 views
5

, um herauszufinden, warum keine Überlastung-Ambiguität in den folgenden Codes verursacht:Pass durch Referenz/Wert Überlastung

float foo2(float& i) 
{ 
    cout << "call from reference" << endl; 
    return i; 
} 
float foo2(float i) 
{ 
    cout << "call from non reference"<<endl; 
    return i; 
} 
int main() 
{ 
    cout<<foo2(2); // print "call from non reference" 
} 

Die foo2, deren Parameter nicht als Referenz übergeben wird aufgerufen. Warum? Wie kann man foo2 aufrufen, die Referenzparameter übergeben?

+1

_ "Wie foo2 aufrufen, die Referenzparameter übergeben?" _ Geben Sie eine Referenz? –

+0

[Der Compiler wird sich über Mehrdeutigkeit beschweren] (http://ideone.com/W5eLdq), wenn Sie versuchen, den mehrdeutigen Anruf zu verwenden. –

+0

Danke alle, Problem gelöst – kchpchan

Antwort

2

Die 2, die Sie als Parameter für foo2 angegeben haben, ist ein rvalue, der keine Referenz sein kann. Die Funktion, die eine Referenz akzeptiert, kann damit nicht aufgerufen werden.

+0

'2' ist keine Rvalue-Referenz, es ist ein Rvalue. Es kann * an eine rvalue-Referenz binden *. (Der Code in der Frage weist keine Mehrdeutigkeit auf, Sie müssten die erste Funktion in "const int & t; otre ambiguity" ändern.) –

+0

@remyabel Oh, Sie haben Recht, behoben. – emlai

5

Die foo2 dessen Parameter nicht Referenz übergeben wird aufgerufen. Warum?

Da Sie eine Konstante oder einen berechneten Ausdruck nicht durch Verweis auf eine Funktion übergeben können, die eine nicht konstante Referenz verwendet. Um einen Ausdruck als Referenz zu übergeben, benötigen Sie einen zuweisbaren Wert - etwas, das auf der linken Seite eines Zuweisungsausdrucks erscheinen kann. Da 2 nicht auf der linken Seite eines Zuweisungsausdrucks angezeigt werden kann, kann er nicht zum Aufrufen einer Funktion verwendet werden, die eine Referenz erwartet. Wenn der Verweis const ist, können Sie alles übergeben, da C++ eine temporäre Variable erstellt, den Ausdruck zuweist und eine Referenz an die Funktion übergibt, die const als Referenz verwendet.

Wie rufen Sie die foo2, die Referenzparameter übergeben?

Es gibt keine offensichtliche Möglichkeit, dies zu tun, denn in dem Moment eine Variable oder einen anderen Ausdruck übergeben, die eine Referenz werden kann, wird der Compiler beschweren sich, dass Sie eine mehrdeutige Anruf machen:

float f; 
foo2(f); // <<== This will not compile 

es gibt einen Weg, es zu nennen, aber: Sie können einen Funktionszeiger, die nur eine der beiden Funktionssignaturen übereinstimmt, und verwenden Sie es auf Ihren Anruf zu machen:

typedef float (*fptr_with_ref)(float&); 

int main() 
{ 
    cout<<foo2(2) << endl; // print "call from non reference" 
    fptr_with_ref foo2ptr(foo2); // Only one overload matches 
    float n = 10; 
    cout<<foo2ptr(n) << endl; // Calls foo2(float&) 
} 

Demo.

+0

Interessanterweise 'int f; foo2 (f); 'kompiliert und führt zu einem Aufruf der Nicht-Referenzfunktion (gerade ausprobiert). Obwohl ich nicht sagen kann warum. (** Bearbeiten ** hat eine Bearbeitung rückgängig gemacht, weil @dasblinkenlight unten beantwortet hat, danke) – jadhachem

+1

@jadhachem Da der Compiler einen Aufruf wie folgt macht: 'foo2 ((float) f)'. Da "f" von "int" in "float" konvertiert werden muss, gibt es keine Mehrdeutigkeit. Wenn Sie 'f' ein' float' machen, würden Sie die Mehrdeutigkeit sehen. – dasblinkenlight

+0

@dasblinkenlight, danke für deine Antwort. Konzept gelöscht. Deine Antwort wurde nicht angezeigt, bevor ich die Seite aktualisiere. – kchpchan

1

Ihre Frage bezieht sich auf C++, nicht auf das Design. C++ unterstützt Dinge auf eine Art und Weise, weil es in Bezug auf Design Sinn macht. C++ erlaubt Ihnen, eine Menge Dinge zu tun, aber wenn Sie gute Software damit machen wollen, können Sie nicht nur an literalen C++ - Regeln festhalten, Sie müssen weiter gehen. In der Praxis bedeutet das, dass du am Ende deine eigenen Regeln aufstellst.

In Ihrem Fall - nun, ich würde nie die Referenzvariante machen, wenn ich nicht wirklich die Variable in der Funktion ändere.

Wenn Sie solche "Regeln" für sich selbst übernehmen, dann sehen Sie sofort, warum die Ref-Funktion nicht bindet: Was ist der Sinn, zuerst eine lose Konstante zu ändern?

Wenn Sie die richtigen Regeln treffen, werden Sie sehen, dass sie wunderbar von C++ unterstützt werden. Like ... Funktion ändert ein Objekt: pass non-const ref. Keine Änderung? const Wahlweise? Zeiger const. Übernahme der Speicherverwaltung? nicht-konstanter Zeiger

Beachten Sie, dass dies erst der Anfang ist, besonders wenn Multithreading ins Spiel kommt. Sie müssen Dinge zum "Vertrag" der Funktion hinzufügen. Beispiel für const ref: Muss das Objekt nach dem Aufruf 'am Leben' bleiben? Kann sich das Objekt während des Gesprächs ändern? Und so weiter.