2017-11-05 3 views
2

Ich lese durch Stroustrup's 4. Ausgabe: The C++ Programming Language. Ich habe einen python/java Hintergrund, also sind die ersten 4 Kapitel bis jetzt in Ordnung.C++: Was macht eigentlich eine De-Referenz?

In Chapter 3 ich sah:

complex& operator+=(complex z) { re+=z.re , im+=z.im; return ∗this; } 

, die einen Tag lang Versuch begann, diese Frage zu schreiben:

Zuerst ich, dass es herausgefunden wird eine Referenz auf das Objekt und nicht eine Kopie zurück. Wie konnte ich in dieser question bestätigen.

Und ich war in der Lage, den Unterschied zwischen der Rückkehr einen Verweis in eine reference variable gegen eine reguläre Variable von diesem question

zu verstehen, und ich habe meine eigene Studie

class Test { 
public: 

    Test():x{5}{} 

    int x; 

    void setX(int a) {x = a;} 

    Test& operator+=(Test z) {x+=z.x; return *this;} 

    // the keyword this is a pointer 
    Test* getTest() {return this;} 

    // but I can return the reference by *this 
    Test& getTest1() {return *this;} 

    // or I can return a copy 
    Test getTest2() {return *this;} 

}; 

Das hat mich führen zu fragen, warum es wird de-reference genannt, so habe ich diesen Versuch

int x = 8; 
int* p = &x; 
int y = *p; 
int& z = *p; 

x++; // let's have some fun 

std::cout << y << std::endl; 
std::cout << z << std::endl; 

Wieerwartetund z = 9, also wie hat die de-reference die address in einem Fall zurückgegeben, und die value in der anderen? Wichtiger noch, wie ist C++ diese Unterscheidung zu machen?

+3

Eine Referenz kann als automatisch dereferenzierter Zeiger betrachtet werden, ist aber keine Adresse. – iksemyonov

+0

@iksemyonov Wenn es keine Adresse oder ein Wert ist, was ist es dann? –

+0

@SamHammamy Eine Adresse ist ein Wert. – melpomene

Antwort

1

Wie erwartet y = 8 und z = 9, also wie hat die De-Referenz die Adresse in einem Fall zurückgegeben, und der Wert in der anderen? Noch wichtiger, wie macht C++ diese Unterscheidung?

Die De-Referenz zurückgegeben die tatsächliche Sache verwiesen in beiden Fällen. Es gibt also keinen Unterschied für C++ zu machen. Der Unterschied besteht darin, was mit dem Ergebnis der Dereferenz gemacht wurde.

Wenn Sie int j = <something>; tun, dann wird das Ergebnis der etwas verwendet, um j zu initialisieren. Da j eine Ganzzahl ist, muss <something> ein ganzzahliger Wert sein.

Wenn Sie int &j = <something>; tun, wird das Ergebnis der etwas noch verwendet, um j zu initialisieren. Aber jetzt ist j eine Referenz auf eine ganze Zahl und die <something> muss eine ganze Zahl sein, nicht nur ein ganzzahliger Wert.

Also, was *this tut ist das gleiche in beiden Fällen. Wie Sie einen Wert verwenden, hat keinen Einfluss darauf, wie dieser Wert berechnet wird. Aber wie Sie es verwenden, wirkt sich darauf aus, was passiert, wenn Sie es verwenden. Und diese beiden Codeteile verwenden das dereferenzierte Objekt anders. In einem Fall wird sein Wert genommen. Im anderen Fall ist eine Referenz an sie gebunden.

+0

Danke David! Also bedeutet das, dass ich 'int & j = irgendeine_funktion 'tun kann: nicht die' Rückkehr ', sondern den' Namen der Funktion'? Damit ich 'j()' später machen kann? –

+0

@SamHammamy Nein, weil eine Funktion keine Referenz zu einem int ist. Da 'j' vom Typ" reference to int "ist, muss das Ding auf der rechten Seite von' = 'ein Verweis auf eine ganze Zahl sein (oder in eine solche umwandelbar sein), keine Funktion. Ein Verweis auf eine Ganzzahl ist auch nicht aufrufbar. Also macht 'j()' keinen Sinn. –

3

Es ist genau wie in Ihrer Test-Klasse Funktionen.

int y = *p; 
int& z = *p; 

y ist eine Kopie von dem, was p Punkte. z ist ein Verweis auf (keine Adresse) was verweist auf. So ändert sich z ändert *p und umgekehrt. Aber die Änderung y hat keine Auswirkungen auf *p.

+0

Danke! Das verdeutlicht es sehr. Aber wenn 'z' keine Adresse ist, was genau dann? Ja, es ist eine "Referenz" zu "x", aber wie ist das dargestellt? Ein symbolischer Link in Linux speichert den Pfad zur Zieldatei. –

+0

Referenzen sind ein eigener Typ. Die Unterschiede zwischen Referenzen und Zeigern sind subtil. Ein wichtiger Unterschied ist, dass Zeiger NULL sein können und Referenzen nicht. Siehe diesen Beitrag für weitere Details. https://stackoverflow.com/questions/57483/what-are-the-differences-between-a-pointer-variable-and-a-reference-variable-in – MFisherKDX

+0

@MFisherKDX IIRC Referenzen sind * angeblich * nie Null sein aber es gibt (wenn auch in der Regel erfundene) Fälle, in denen sie missbraucht werden können, um auf Nullwerte zu verweisen (oder zumindest war es in einer Version von C++ möglich). – errantlinguist

1

Es ist möglich, einen Zeiger int* p als Verweis auf eine Adresse zu betrachten, in der sich Daten vom Typ int befinden. Wenn Sie dies rückgängig machen, ruft das System den Wert an dieser Speicheradresse ab (die Adresse ist der tatsächliche Wert von selbst). Im Fall von int y = *p; legen Sie eine Kopie dieses Wertes auf den Stapel als locator valuey.

Auf der anderen Seite, de-Referenzierung auf der linke Seite in *p = 13; bedeutet, dass Sie den Wert int*p an der Speicheradresse durch den Wert von p mit dem rechten seitigen Wert 13 bezeichnet gespeichert sind, zu ersetzen.

Der Referenz lvalue int& z in int& z = *p; ist nicht eine Kopie des int Wert von p zeigte, sondern eine linke Seite Bezug auf was auch immer an der jeweiligen Speicheradresse durch *p (dh der tatsächliche Wert gehalten zurück durch selbst).

Dies bedeutet nicht viel Unterschied in Ihrem erfundenen Fall, aber z.B.eine Foo Klasse mit einem Foo::incrementCount() Wert gegeben,

Foo* p = new Foo(); 
p->incrementCount(); 

Foo& ref = *p; 
ref.incrementCount(); 

Das gleiche Verfahren für die gleiche Instanz wird zweimal aufgerufen werden. Im Gegensatz dazu kopiert Foo foo = *p tatsächlich die gesamte Foo Instanz und erstellt eine separate Kopie auf dem Stapel. Daher wirkt sich das Aufrufen von foo.incrementValue() nicht auf das separate Objekt aus, auf das weiterhin von verwiesen wird.