Referenz (C ++) – Wikipedia

before-content-x4

In der Programmiersprache C ++ a Referenz ist ein einfacher Referenzdatentyp, der weniger leistungsfähig, aber sicherer als der von C geerbte Zeigertyp ist. Der Name C ++ – Referenz kann Verwirrung stiften, da in der Informatik eine Referenz ein allgemeiner Konzeptdatentyp ist, mit Zeiger und C ++ – Referenzen als spezifische Referenzdatentypimplementierungen. Die Definition einer Referenz in C ++ ist so, dass sie nicht existieren muss. Es kann als neuer Name für ein vorhandenes Objekt implementiert werden (ähnlich wie beim Umbenennen des Schlüsselworts in Ada).

Syntax und Terminologie[edit]

Die Erklärung des Formulars:

& 

wo ist ein Typ und ist eine Kennung, deren Typ ist Bezug auf .

Beispiele:

int a = 5;
int& r_a = a;

extern int& r_b;

Hier, r_a und r_b sind vom Typ “Verweis auf int“”

Foo ist eine Funktion, die einen “Verweis auf” zurückgibt int“”

Bar ist eine Funktion mit einem Referenzparameter, der eine “Referenz auf” ist int“”

after-content-x4
class MyClass { int& m_b; /* ... */ };

MyClass ist ein class mit einem Mitglied, auf das Bezug genommen wird int

int FuncX() { return 42 ; };
int (&f_func)() = FuncX;

FuncX ist eine Funktion, die einen (Nichtreferenztyp) zurückgibt. int und f_func ist ein alias zum FuncX

const int& ref ist eine konstante Referenz, die auf ein Speicherstück mit dem Wert 65 zeigt.

Typen, auf die “Bezug genommen wird” “werden manchmal genannt Referenztypen. Bezeichner vom Referenztyp werden aufgerufen Referenzvariablen. Um sie anzurufen Variableist jedoch in der Tat eine Fehlbezeichnung, wie wir sehen werden.

Beziehung zu Zeigern[edit]

C ++ – Referenzen unterscheiden sich von Zeigern in mehreren wesentlichen Punkten:

  • Es ist nicht möglich, direkt auf ein Referenzobjekt zu verweisen, nachdem es definiert wurde. Jedes Vorkommen seines Namens bezieht sich direkt auf das Objekt, auf das er verweist.
  • Sobald eine Referenz erstellt wurde, kann sie später nicht mehr als Referenz für ein anderes Objekt verwendet werden. es kann nicht sein wieder eingesetzt. Dies geschieht häufig mit Zeigern.
  • Referenzen können nicht sein Null, während Zeiger können; Jede Referenz bezieht sich auf ein Objekt, obwohl es gültig sein kann oder nicht. Beachten Sie, dass aus diesem Grund Referenzcontainer nicht zulässig sind.
  • Referenzen können nicht nicht initialisiert werden. Da es unmöglich ist, eine Referenz neu zu initialisieren, müssen sie sofort nach ihrer Erstellung initialisiert werden. Insbesondere müssen lokale und globale Variablen dort initialisiert werden, wo sie definiert sind, und Referenzen, die Datenelemente von Klasseninstanzen sind, müssen in der Initialisierungsliste des Konstruktors der Klasse initialisiert werden. Zum Beispiel:
    int& k; // compiler will complain: error: `k' declared as reference but not initialized
    

Es gibt eine einfache Konvertierung zwischen Zeigern und Referenzen: die Adresse des Operators (&) ergibt einen Zeiger, der sich auf dasselbe Objekt bezieht, wenn er auf eine Referenz angewendet wird, und eine Referenz, die aus der Dereferenzierung initialisiert wird (*) eines Zeigerwerts bezieht sich auf dasselbe Objekt wie dieser Zeiger, wobei dies möglich ist, ohne undefiniertes Verhalten aufzurufen. Diese Äquivalenz spiegelt die typische Implementierung wider, bei der Referenzen effektiv zu Zeigern zusammengefasst werden, die bei jeder Verwendung implizit dereferenziert werden. Obwohl dies normalerweise der Fall ist, zwingt der C ++ – Standard Compiler nicht dazu, Referenzen mithilfe von Zeigern zu implementieren.

Dies hat zur Folge, dass in vielen Implementierungen das Bearbeiten einer Variablen mit automatischer oder statischer Lebensdauer über eine Referenz, obwohl syntaktisch dem direkten Zugriff ähnlich, versteckte Dereferenzierungsoperationen beinhalten kann, die kostspielig sind.

Da die Operationen für Referenzen so begrenzt sind, sind sie viel einfacher zu verstehen als Zeiger und widerstandsfähiger gegen Fehler. Während Zeiger durch eine Vielzahl von Mechanismen ungültig gemacht werden können, angefangen beim Übertragen eines Nullwerts über unregelmäßige Arithmetik bis hin zu illegalen Casts und deren Erzeugung aus beliebigen Ganzzahlen, wird eine zuvor gültige Referenz nur in zwei Fällen ungültig:

  • Wenn es sich um ein Objekt mit automatischer Zuordnung handelt, das außerhalb des Gültigkeitsbereichs liegt,
  • Wenn es sich auf ein Objekt in einem freigegebenen Block des dynamischen Speichers bezieht.

Die erste ist leicht automatisch zu erkennen, wenn die Referenz einen statischen Gültigkeitsbereich hat, ist jedoch immer noch ein Problem, wenn die Referenz Mitglied eines dynamisch zugewiesenen Objekts ist. Der zweite ist schwieriger zu erkennen. Dies sind die einzigen Bedenken in Bezug auf Referenzen und werden durch eine angemessene Zuweisungsrichtlinie angemessen berücksichtigt.

Verwendung von Referenzen[edit]

  • Abgesehen von einem hilfreichen Ersatz für Zeiger besteht eine bequeme Anwendung von Referenzen in Funktionsparameterlisten, in denen die für die Ausgabe verwendeten Parameter ohne explizite Adressübernahme durch den Aufrufer übergeben werden können. Zum Beispiel:
void Square(int x, int& out_result) {
  out_result = x * x;
}

Dann würde der folgende Anruf 9 in platzieren y::

Der folgende Aufruf würde jedoch einen Compilerfehler ergeben, da Referenzparameter nicht mit qualifiziert sind const kann nur an adressierbare Werte gebunden werden:

  • Durch die Rückgabe einer Referenz können Funktionsaufrufe zugewiesen werden:
    int& Preinc(int& x) {
      return ++x;  // "return x++;" would have been wrong
    }
    
    Preinc(y) = 5;  // same as ++y, y = 5
    
  • In vielen Implementierungen implizieren normale Parameterübergabemechanismen häufig eine teure Kopieroperation für große Parameter. Referenzen qualifiziert mit const sind eine nützliche Methode zum Übergeben großer Objekte zwischen Funktionen, die diesen Overhead vermeidet:
    void FSlow(BigObject x) { /* ... */ }  
    void FFast(const BigObject& x) { /* ... */ }
    
    BigObject y;
    
    FSlow(y);  // Slow, copies y to parameter x.
    FFast(y);  // Fast, gives direct read-only access to y.
    

Wenn FFast erfordert tatsächlich eine eigene Kopie von x Damit es geändert werden kann, muss es explizit eine Kopie erstellen. Während die gleiche Technik unter Verwendung von Zeigern angewendet werden könnte, würde dies das Ändern jeder Aufrufstelle der Funktion beinhalten, um eine umständliche Adresse von (&) Operatoren auf das Argument und wäre ebenso schwer rückgängig zu machen, wenn das Objekt später kleiner würde.

Polymorphes Verhalten[edit]

In Fortsetzung der Beziehung zwischen Referenzen und Zeigern (im C ++ – Kontext) weisen die ersteren polymorphe Fähigkeiten auf, wie zu erwarten:

#include 

class A {
 public:
  A() = default;
  virtual void Print() { std::cout << "This is class An"; }
};

class B : public A {
 public:
  B() = default;
  virtual void Print() { std::cout << "This is class Bn"; }
};

int main() {
  A a;
  A& ref_to_a = a;

  B b;
  A& ref_to_b = b;

  ref_to_a.Print();
  ref_to_b.Print();
}

Die obige Quelle ist gültiges C ++ und generiert die folgende Ausgabe:

This is class A

This is class B

ISO-Definition[edit]

Referenzen werden vom ISO C ++ – Standard wie folgt definiert (mit Ausnahme des Beispielabschnitts):

In einer Erklärung TD, in der D die Form hat

und der Typ des Bezeichners in der Deklaration T D1 ist “abgeleitete Deklarator-Typ-Liste T, “dann ist der Typ der Kennung von D”abgeleitete Deklarator-Typ-Liste Bezug auf T. “Lebenslaufqualifizierte Referenzen sind schlecht geformt, außer wenn die Lebenslaufqualifizierer (const und flüchtig) werden durch die Verwendung von a eingeführt typedef (7.1.3) oder eines Argumentes vom Typ Vorlage (14.3). In diesem Fall werden die Lebenslaufqualifizierer ignoriert. [Example: in

typedef int& A;
const A aref = 3;  // ill-formed;
// non-const reference initialized with rvalue

the type of aref is “reference to int“, not “const reference to int“. ] [Note: a reference can be thought of as a name of an object. ] Ein Deklarator, der den Typ “Verweis auf” angibt Lebenslauf void “ist schlecht geformt.

Es ist nicht angegeben, ob eine Referenz gespeichert werden muss oder nicht (3.7).

Es dürfen keine Verweise auf Verweise, keine Verweise auf Verweise und keine Verweise auf Verweise vorhanden sein. Die Referenzerklärung enthält eine Initialisierer (8.5.3) außer wenn die Erklärung eine explizite enthält extern Der Bezeichner (7.1.1) ist eine Deklaration eines Klassenmitglieds (9.2) innerhalb einer Klassendeklaration oder die Deklaration eines Parameters oder eines Rückgabetyps (8.3.5). siehe 3.1. Eine Referenz muss initialisiert werden, um auf ein gültiges Objekt oder eine gültige Funktion zu verweisen. [Note: in particular, a null reference cannot exist in a well-defined program, because the only way to create such a reference would be to bind it to the “object” obtained by dereferencing a null pointer, which causes undefined behavior. As described in 9.6, a reference cannot be bound directly to a bitfield. ]

– –ISO / IEC 14882: 1998 (E), die ISO C ++ – Norm, in Abschnitt 8.3.2 [dcl.ref]

Externe Links[edit]

Verweise[edit]


after-content-x4