Başvuru (C ++) - Reference (C++)

İçinde C ++ Programlama dili, bir referans basit referans daha az güçlü ancak daha güvenli veri türü Işaretçi türden devralınan C. İsim C ++ başvurusu bilgisayar biliminde bir referans genel bir kavram veri türü olduğu için kafa karışıklığına neden olabilir. işaretçiler ve C ++ referansları spesifik referans veri türü uygulamaları. 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 tip ve <Name> bir tanımlayıcı kimin tipi referans <Type>.

Örnekler:

int a = 5;int& r_a = a;dış int& r_b;

Buraya, r_a ve r_b "referans türü" int"

int& Foo();

Foo bir "başvuru" döndüren bir işlevdir int"

geçersiz Bar(int& r_p);

Bar referans parametresine sahip bir işlevdir ve " int"

sınıf Sınıfım { int& m_b; /* ... */ };

Sınıfım bir sınıf referans olan bir üye ile int

int FuncX() { dönüş 42 ; };int (&f_func)() = FuncX;

FuncX (başvuru olmayan tür) döndüren bir işlevdir int ve f_func bir takma ad için FuncX

sabit int& ref = 65;

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

Tür olan türler "referans <Type>"bazen denir referans türleri. Referans türü olan tanımlayıcılar denir referans değişkenleri. Onları aramak için değişkenancak, göreceğimiz gibi, aslında yanlış bir adlandırma.

İşaretçilerle ilişki

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

  • Tanımlandıktan sonra bir referans nesneye doğrudan atıfta bulunmak mümkün değildir; adının herhangi bir geçişi, doğrudan referans verdiği nesneye atıfta bulunur.
  • Bir referans oluşturulduktan sonra, daha sonra başka bir nesneye referans verilemez; olamaz yeniden yerleştirildi. Bu genellikle işaretçilerle yapılır.
  • Referanslar olamaz boşişaretçiler ise; her referans, geçerli olsa da olmasa da bir nesneye atıfta bulunur. Bu nedenle, kapsayıcı referanslara izin verilmediğini unutmayın.
  • Referanslar sıfırlanamaz. Bir referansı yeniden başlatmak mümkün olmadığından, 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 kurucusunun başlatıcı listesinde başlatılmalıdır. Örneğin:
    int& k; // derleyici şikayet edecek: hata: "k 'referans olarak bildirildi, ancak başlatılmadı

İşaretçiler ve referanslar arasında basit bir dönüşüm vardır: operatörün adresi (&) bir referansa uygulandığında aynı nesneye başvuran bir işaretçi ve referansdan başlatılan bir referans (*) bir işaretçi değeri, bu işaretçi ile aynı nesneyi ifade eder, burada bu, tanımsız davranışı çağırmadan mümkündür. Bu eşdeğerlik, referansları her kullanımda dolaylı olarak başvurulan işaretçiler halinde etkin bir şekilde derleyen tipik uygulamanın bir yansımasıdır. Genelde durum bu olsa da, C ++ Standardı, derleyicileri işaretçiler kullanarak başvuruları uygulamaya zorlamaz.

Bunun bir sonucu, birçok uygulamada, bir referans aracılığıyla otomatik veya statik ömre sahip bir değişken üzerinde çalışmak, buna sözdizimsel olarak doğrudan erişime benzer olsa da, maliyetli olan gizli referans işlemlerini içerebilir.

Ayrıca, referanslar üzerindeki işlemler çok sınırlı olduğu için, işaretçilerden anlaşılması çok daha kolaydır ve hatalara karşı daha dirençlidir. İşaretçiler, bir boş değer taşımaktan sınır dışı aritmetiğe ve bunları rastgele tam sayı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.

Birincisi, referansın statik kapsama sahip olup olmadığını otomatik olarak algılamak kolaydır, ancak referans dinamik olarak ayrılmış bir nesnenin üyesi ise yine de bir sorundur; ikincisini tespit etmek daha zordur. Bunlar referanslarla ilgili tek endişelerdir ve makul bir tahsis politikası ile uygun şekilde ele alınmıştır.

Referansların kullanımı

  • İşaretçiler için yararlı bir ikame dışında, uygun bir referans uygulaması, çağıran tarafından açık bir adres alma olmaksızın çıktı için kullanılan parametrelerin geçişine izin veren işlev parametre listelerinde yer alır. Örneğin:
geçersiz Meydan(int x, int& out_result) {  out_result = x * x;}

Ardından, aşağıdaki çağrı, y:

int y;Meydan(3, y);

Ancak, aşağıdaki çağrı bir derleyici hatası verir, çünkü referans parametreleri sabit yalnızca adreslenebilir değerlere bağlanabilir:

Meydan(3, 6);
  • Bir referansın geri döndürülmesi, işlev çağrılarının atanmasına izin verir:
    int& Preinc(int& x) {  dönüş ++x;  // "x ++ döndür;" yanlış olurdu}Preinc(y) = 5;  // ++ y, y = 5 ile aynı
  • Çoğu uygulamada, normal parametre geçirme mekanizmaları genellikle büyük parametreler için pahalı bir kopyalama işlemi gerektirir. Nitelikli referanslar sabit bu ek yükten kaçınan işlevler arasında büyük nesneler geçirmenin kullanışlı bir yoludur:
    geçersiz FSlow(BigObject x) { /* ... */ }  geçersiz Hızlı(sabit BigObject& x) { /* ... */ }BigObject y;FSlow(y);  // Yavaş, y'yi x parametresine kopyalar.Hızlı(y);  // Hızlı, y'ye doğrudan salt okunur erişim sağlar.

Eğer Hızlı aslında kendi kopyasını gerektirir x değiştirebileceğini, açıkça bir kopya oluşturması gerekir. Aynı teknik işaretçiler kullanılarak uygulanabilse de, bu işlevin her arama sitesini hantal adres (&) argümanın operatörlerini kullanır ve nesne daha sonra küçülürse, geri alınması eşit derecede zor olacaktır.

Polimorfik davranış

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

#Dahil etmek <iostream>sınıf Bir { halka açık:  Bir() = varsayılan;  gerçek geçersiz Yazdır() { std::cout << "Bu A sınıfı n"; }};sınıf B : halka açık Bir { halka açık:  B() = varsayılan;  gerçek geçersiz Yazdır() { std::cout << "Bu B sınıfı n"; }};int ana() {  Bir a;  Bir& ref_to_a = a;  B b;  Bir& ref_to_b = b;  ref_to_a.Yazdır();  ref_to_b.Yazdır();}

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

Bu B sınıfı

ISO tanımı

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

T D beyannamesinde D'nin forma sahip olduğu

& D1

ve T D1 bildirimindeki tanımlayıcının türü "türetilmiş bildirimci tür listesi T, "o zaman D'nin tanımlayıcısının türü"türetilmiş bildirimci tür listesi referans T. "Cv nitelikli referanslar, cv niteleyicilerinin (sabit ve uçucu) bir typedef (7.1.3) veya bir şablon türü bağımsız değişkeni (14.3), bu durumda cv niteleyicileri yok sayılır. [Misal: içinde

typedef int& Bir;sabit Bir Aref = 3;  // biçimsiz;// rvalue ile başlatılan const olmayan referans

türü Aref "referans int", değil "sabit referans int". ] [Not: bir referans, bir nesnenin adı olarak düşünülebilir. ] Tip "başvurusunu" belirten bir bildirici Özgeçmiş void "kötü biçimlidir.

Bir referansın depolamaya ihtiyaç duyup duymadığı belirtilmemiştir (3.7).

Referanslara referanslar, referans dizileri ve referanslara işaretçiler olmayacaktır. Bir referansın beyanı, bir başlatıcı (8.5.3) bildirimin açık bir dış tanımlayıcı (7.1.1), bir sınıf bildirimi içindeki bir sınıf üyesi (9.2) bildirimi veya bir parametrenin bildirimi veya bir dönüş türü (8.3.5); bkz. 3.1. Geçerli bir nesneye veya işleve atıfta bulunmak için bir referans başlatılmalıdır. [Not: özellikle, iyi tanımlanmış bir programda boş bir referans olamaz, çünkü böyle bir referans oluşturmanın tek yolu, onu, tanımsız davranışa neden olan bir boş göstericiye başvurarak 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'de [dcl.ref]

Dış bağlantılar

Referanslar