Referans (C++) - Reference (C++)

In C ++ dilini programlama , bir referans basit bir referans az güçlü fakat daha güvenlidir veri türü işaretçisi miras tip C . Bilgisayar biliminde bir referans, işaretçiler ve C++ referansları özel referans veri türü uygulamaları olan genel bir kavram veri türü olduğundan, C++ referansı adı karışıklığa neden olabilir . C++'da bir referansın tanımı, var olması gerekmeyecek şekildedir. Mevcut bir nesne için yeni bir ad olarak uygulanabilir (Ada'daki anahtar kelimeyi yeniden adlandırmaya benzer).

Sözdizimi ve terminoloji

Formun beyanı:

<Type>& <Name>

nerede <Type>bir türdür ve türü referans olan <Name>bir tanımlayıcıdır . <Type>

Örnekler:

int a = 5;
int& r_a = a;

extern int& r_b;

Burada r_ave r_b"referans int" türündendirler

int& Foo();

FooBir "referans döndüren fonksiyondur int"

void Bar(int& r_p);

BarBir "referans bir referans parametresi olan bir fonksiyonu olan int"

class MyClass { int& m_b; /* ... */ };

MyClassa, classbir referans olan bir üyesiyleint

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

FuncXbir (referans olmayan tür) döndüren intve f_funcbunun için bir takma ad olan bir işlevdir.FuncX

const int& ref = 65;

const int& ref 65 değerine sahip bir depolama parçasına işaret eden sabit bir referanstır.

"Referans <Type>" türündeki türlere bazen referans türleri denir . Referans türündeki tanımlayıcılara referans değişkenleri denir . Ancak, göreceğimiz gibi onları değişken olarak adlandırmak aslında bir yanlış isimdir.

işaretçilerle ilişki

C++ referansları, birkaç temel yönden işaretçilerden farklıdır:

  • Tanımlandıktan sonra bir referans nesnesine doğrudan atıfta bulunmak mümkün değildir; adının herhangi bir şekilde geçmesi, doğrudan başvurduğu nesneye atıfta bulunur.
  • Bir referans oluşturulduktan sonra, daha sonra başka bir nesneye referans olarak yapılamaz; o edilemez reseated . Bu genellikle işaretçilerle yapılır.
  • Referanslar null olamaz , ancak işaretçiler; her referans, geçerli olabilir veya olmayabilir de, bir nesneye atıfta bulunur. Bu nedenle, referans kapsayıcılarına izin verilmediğini unutmayın.
  • Referanslar başlatılamaz. Bir referansı yeniden başlatmak imkansız olduğundan, oluşturuldukları anda başlatılmaları gerekir. Özellikle, yerel ve global değişkenler tanımlandıkları yerde başlatılmalıdır ve sınıf örneklerinin veri üyeleri olan referanslar, sınıfın yapıcısının başlatıcı listesinde başlatılmalıdır. Örneğin:
    int& k; // compiler will complain: error: `k' declared as reference but not initialized
    

&İşaretçiler ve referanslar arasında basit bir dönüşüm vardır: operatörün adresi ( ), bir referansa uygulandığında aynı nesneye atıfta *bulunan bir işaretçi verir ve bir işaretçi değerinin referansından ( ) başlatılan bir referans, başvuruda bulunur. bu işaretçiyle aynı nesne, burada tanımsız davranışa başvurmadan bu mümkün. Bu eşdeğerlik, referansları her kullanımda dolaylı olarak başvurulan işaretçilere etkin bir şekilde derleyen tipik uygulamanın bir yansımasıdır. Bu genellikle böyle olsa da, C++ Standardı derleyicileri işaretçiler kullanarak referansları uygulamaya zorlamaz.

Bunun bir sonucu olarak, birçok uygulamada, sözdizimsel olarak doğrudan erişmeye benzer olmasına rağmen, bir referans aracılığıyla otomatik veya statik ömrü olan bir değişken üzerinde çalışmak, maliyetli olan gizli başvuru işlemlerini gerektirebilir.

Ayrıca, referanslar üzerindeki işlemler çok sınırlı olduğu için, işaretçilere göre anlaşılması çok daha kolaydır ve hatalara karşı daha dirençlidir. İşaretçiler, boş bir değer taşımaktan sınır dışı aritmetiklere, yasadışı yayınlara ve bunları keyfi tamsayılardan üretmeye kadar çeşitli mekanizmalarla geçersiz kılınabilirken, önceden geçerli bir referans yalnızca iki durumda geçersiz hale gelir:

  • Kapsam dışına çıkan otomatik tahsisli bir nesneye atıfta bulunuyorsa,
  • Serbest bırakılmış bir dinamik bellek bloğu içindeki bir nesneye atıfta bulunuyorsa.

İlki, başvurunun statik kapsamı varsa otomatik olarak algılanması kolaydır, ancak başvuru dinamik olarak tahsis edilmiş bir nesnenin üyesiyse yine de sorun teşkil eder; ikincisini tespit etmek daha zordur. Bunlar, referanslarla ilgili tek endişedir ve makul bir tahsis politikasıyla uygun şekilde ele alınır.

referansların kullanımları

  • İşaretçiler için yararlı bir değiştirme dışında, uygun bir başvuru uygulaması, arayan tarafından açık bir adres almadan çıktı için kullanılan parametrelerin iletilmesine izin verdikleri işlev parametre listeleridir. Örneğin:
void Square(int x, int& out_result) {
  out_result = x * x;
}

Ardından, aşağıdaki çağrı y'ye 9 yerleştirir :

int y;
Square(3, y);

Bununla birlikte, aşağıdaki çağrı bir derleyici hatası verir, çünkü nitelenmeyen referans parametreler constyalnızca adreslenebilir değerlere bağlanabilir:

Square(3, 6);
  • Bir referans döndürmek, işlev çağrılarının şunlara atanmasını sağlar:
    int& Preinc(int& x) {
      return ++x;  // "return x++;" would have been wrong
    }
    
    Preinc(y) = 5;  // same as ++y, y = 5
    
  • Birçok uygulamada, normal parametre geçiş mekanizmaları genellikle büyük parametreler için pahalı bir kopyalama işlemi anlamına gelir. Nitelikli referanslar const, bu ek yükü önleyen işlevler arasında büyük nesneleri geçirmenin kullanışlı bir yoludur:
    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.
    

Eğer FFastgerçekte kendi kopyasını gerektirir x o değiştirebileceğiniz, açıkça bir kopyasını oluşturmak gerekir. Aynı teknik işaretçiler kullanılarak uygulanabilirken, bu &, argümana hantal adres-of ( ) operatörleri eklemek için işlevin her çağrı sitesini değiştirmeyi içerir ve nesne daha sonra küçülürse geri almak eşit derecede zor olurdu.

polimorfik davranış

Referanslar ve işaretçiler arasındaki ilişkiyi sürdürürken (C++ bağlamında), ilki beklendiği gibi polimorfik yetenekler sergiler:

#include <iostream>

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

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

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

  B b;
  A& ref_to_b = b;

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

Yukarıdaki kaynak geçerli C++'dır ve aşağıdaki çıktıyı üretir:

This is class A

This is class B

ISO tanımı

Referanslar, ISO C++ standardı tarafından aşağıdaki şekilde tanımlanmıştır (örnek bölüm hariç):

D'nin forma sahip olduğu bir bildirimde TD

& D1

ve T D1 bildirimindeki tanımlayıcının türü " türetilmiş-bildirici-tür-listesi T " ise, o zaman D'nin tanımlayıcısının türü " türetilmiş-bildirici-tip-liste referansı T" olur . Özgeçmiş niteleyicileri ( constve uçucu ) bir typedef(7.1.3) veya bir şablon türü argümanı (14.3) kullanılarak tanıtıldığında , bu durumda özgeçmiş niteleyicileri yoksayıldığı durumlar dışında, özgeçmiş nitelikli başvurular hatalı biçimlendirilmiştir . [ Örnek : içinde

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

tipi aref"referans int" değil, " constreferans " tır int. ] [ Not : bir referans, bir nesnenin adı olarak düşünülebilir. ] " cv void referansı" türünü belirten bir bildirici hatalı biçimlendirilmiş.

Bir referansın saklama gerektirip gerektirmediği belirtilmemiştir (3.7).

Referanslara referanslar, referans dizileri ve referanslara işaretçiler olmayacaktır. Bir ihtiva eder referans beyanı başlatıcı bildirimi açık bir içerdiğinde dışında (8.5.3) externbelirtici (7.1.1), bir sınıf üyesi bir sınıf bildirimi içinde (9.2) bildirimi, ya da bir parametre veya a bildirimidir dönüş türü (8.3.5); 3.1'e bakın. Geçerli bir nesneye veya işleve atıfta bulunmak için bir referans başlatılacaktır. [ Not : özellikle, iyi tanımlanmış bir programda boş bir başvuru olamaz, çünkü böyle bir başvuru oluşturmanın tek yolu, onu tanımsız davranışa neden olan bir boş göstericinin başvurusunu kaldırarak elde edilen "nesneye" bağlamak olacaktır. 9.6'da açıklandığı gibi, bir referans doğrudan bir bit alanına bağlanamaz. ]

—  ISO/IEC 14882:1998(E), ISO C++ standardı, bölüm 8.3.2 [dcl.ref]

Dış bağlantılar

Referanslar