---
title: Referanslar
source: 'https://academia.sh/tr/kurslar/cpp-temelleri/referanslar'
course: 'C++ Temelleri ve Nesne Tasarımı'
language: tr
updated: '2026-09-26T03:02:46+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Bir referans parametresinin çağıranın kendi nesnesiyle çalıştığını ölçer'
    - 'Değer, referans ve const referans arasında ne zaman hangisinin seçileceğini uygular'
    - 'const referansın geçici bir nesneye bağlanabildiğini, sıradan referansın bağlanamadığını ayırt eder'
---

# Referanslar

Bir referans parametresinin çağıranın kendi nesnesiyle çalıştığını, hiçbir kopya üretmediğini ölçer.

Önceki ders bir nesnenin kopyalandığında kendi belleğini aldığını ölçtü. Bu ders tam tersi
bir soruyu ölçer: bir işlev bir nesneyi **referansla** alırsa, hiç kopya üretilir mi, yoksa
işlev doğrudan çağıranın kendi nesnesiyle mi çalışır? Ölçüm sınıfı **kendisi**: `tasi(Nokta&
n)` işlevine `p` verildiğinde, işlevin içindeki `n` ile çağırandaki `p` aynı nesnedir —
`&p == &n` doğrudur, aralarında hiçbir kopyalama adımı yoktur.

C'de bir işleve bir yapıyı "referansla" aktarmanın tek yolu bir işaretçi geçirmekti:
`tasi(&p)`, işlev içinde `(*ptr).x` ya da `ptr->x` ile erişim. Bu, çağıran tarafında
`&` operatörünün elle yazılmasını, işlev içinde de her erişimde bir yıldızlamanın (`*`)
ya da ok işlecinin gerekmesini zorunlu kılardı — ve `ptr`'nin `nullptr` olma ihtimali her
zaman vardı. C++'ta referans bu iki sorunu birden kaldırır: çağıran tarafında `tasi(p)`
yazılır, `&` gerekmez; işlev içinde `n.x` yazılır, yıldızlama gerekmez; ve bir referans
kurulmadan bırakılamayacağı için `nullptr` durumu dilin kendisi tarafından engellenir.

## Referans Nedir

Bir **referans** (reference), var olan bir nesneye verilen ikinci bir addır — yeni bir
nesne değildir, yeni bir bellek adresi de almaz. `Nokta& r = p;` yazıldığında `r`, `p`'nin
kendisidir; `r` üzerinden yapılan her okuma ve yazma doğrudan `p`'nin belleğine ulaşır.
Bu, bir işaretçiden (`Nokta* ptr = &p;`) farklıdır: işaretçi ayrı bir nesnedir, kendi
belleğine sahiptir ve `p`'nin adresini **tutar**; referans ise `p`'nin kendisiyle **aynı**
şeydir, ayrı bir bellek konumu işgal etmez (derleyici çoğu zaman referansı bir işaretçi
gibi koda çevirir, ama dilin kendi modelinde referans yeni bir nesne değildir).

Bu ayrımın pratik sonucu şudur: bir işaretçi `ptr->x` yazmadan önce geçerli bir nesneye
işaret ettiğini garanti etmez, elle denetlenmesi gerekebilir (`if (ptr != nullptr)`). Bir
referans için böyle bir denetim yoktur ve gerekmez — dil, bir referansın her zaman geçerli
bir nesneye bağlı olduğunu varsayar (bu varsayımı kasıtlı olarak kıran, örneğin geçersiz
bir işaretçiyi yıldızlayıp bir referansa bağlayan kod, tanımsız davranış üretir, ama bu
dersin kapsamındaki hiçbir kod böyle bir şey yapmaz). Bu yüzden referans alan bir işlev
imzası, işaretçi alan bir imzadan daha az savunma kodu gerektirir — parametrenin var
olduğu baştan kabul edilir.

```cpp
// nokta.hpp — referansla aktarim olcumu icin basit bir yapi
#ifndef NOKTA_HPP
#define NOKTA_HPP

struct Nokta {
    int x;
    int y;
};

#endif
```

## Referansla Aktarılan Yapı

```cpp
// referans-olcumu.cpp — tasi(Nokta&) cagiranin kendi nesnesiyle mi calisiyor
#include <cstdio>

#include "nokta.hpp"

void tasi(Nokta& n, Nokta* cagiranAdresi) {
    std::printf("tasi icindeki n cagiranla ayni nesne mi %s\n",
                &n == cagiranAdresi ? "evet" : "hayir");
    n.x += 10;
    n.y += 10;
}

int main() {
    Nokta p{1, 2};

    tasi(p, &p);

    std::printf("tasidan sonra p.x=%d p.y=%d\n", p.x, p.y);
    return 0;
}
```

```text
tasi icindeki n cagiranla ayni nesne mi evet
tasidan sonra p.x=11 p.y=12
```

**SK12.** `tasi(Nokta& n, Nokta* cagiranAdresi)` argümanını referansla alır;
`tasi(p, &p)` çağrıldığında `n`, `p`'nin **kendisidir** — `&n == cagiranAdresi` (yani
`&n == &p`) doğrudur. `n.x += 10;` satırı `n` üzerinden yazsa da, `n` ile `p` aynı nesne
olduğu için bu yazma doğrudan `p.x`'i değiştirir; `tasi` döndükten sonra `p.x` ve `p.y`
zaten güncellenmiştir (`11` ve `12`) — `main` hiçbir dönüş değeri almadan, hiçbir atama
yapmadan çağıranın nesnesi değişmiş olarak devam eder. Bu, bir önceki dersin **kopya**
sınıfının tam karşıtıdır: orada `b`, `a`'dan adres olarak farklıydı; burada `n`, `p` ile
**aynı** adrestir — hiçbir kopyalama adımı çalışmaz, çünkü referans argümanı
aktarmak kopyalayan yapıcıyı hiç çağırmaz.

## Değer, Referans, const Referans: Ne Zaman Hangisi

Bir işlev bir nesneyi argüman olarak alırken üç seçenek vardır, ve her biri
farklı bir niyeti kodlar:

- **Değerle** (`Nokta n`): işlev kendi kopyasıyla çalışır, çağıranın nesnesini hiçbir
  biçimde etkilemez. Küçük, ucuz kopyalanan tipler için (bir `int`, iki `int`'lik bir
  `Nokta`) uygundur; büyük ya da pahalı kopyalanan tipler için (üçüncü dersteki `Tampon`
  gibi kendi belleğini yöneten bir sınıf) her çağrıda gereksiz bir kopya üretir.
- **Referansla** (`Nokta& n`): işlev çağıranın nesnesiyle doğrudan çalışır, onu
  **değiştirebilir**. `tasi` bunu yapar — imzası okuyana "bu işlev verdiğin nesneyi
  değiştirebilir" der.
- **const referansla** (`const Nokta& n`): işlev çağıranın nesnesine kopyasız erişir ama
  onu **değiştiremez** — `n.x += 10;` burada bir derleme hatası olurdu. Bu, "büyük bir
  nesneyi ucuza oku, ama değiştirme" niyetini kodlar; önceki derslerdeki kopyalayan
  yapıcı ve kopyalayan atamanın argümanı de tam bu yüzden `const Tampon&`dı.

İmza okunarak niyet anlaşılır: `void yaz(const Nokta& n)` çağıranın nesnesini yalnız okur;
`void tasi(Nokta& n)` değiştirir; `void kopyala(Nokta n)` hiç dokunmaz, kendi kopyasında
çalışır.

Bu üç seçenek arasında "her zaman referans kullan, daha hızlı" gibi bir kısayol yoktur.
`int` gibi küçük, tek bir makine kelimesine sığan bir tipi referansla almak genellikle
hiçbir şey kazandırmaz — bir referansı geçirmek de (derleyicinin ürettiği koda göre)
genellikle bir adres geçirmek anlamına gelir, ve bir adres de tipik olarak bir `int` ile
aynı büyüklüktedir; üstelik referans alan bir işlev artık çağıranın nesnesini
değiştirebileceği için, salt-okunur bir kullanım bile yanlışlıkla bir yazmaya açık hâle
gelir (bu risk `const int&` ile kapanır, ama o zaman da kazanç kalmaz). Değerle almak
küçük tipler için hem daha basit hem çoğunlukla eşit hızlıdır. Referans ve const
referansın asıl kazancı, kopyalaması pahalı olan tipler için ortaya çıkar — üçüncü ve
beşinci derslerdeki `Tampon` gibi kendi belleğini ayıran sınıflar, ya da çok sayıda üyesi
olan büyük yapılar.

## Referans Parametreler ve Dönüş Değerleri

Referans yalnız parametrelerde değil, dönüş tiplerinde de kullanılabilir. `Nokta&
ilki(Nokta dizi[])` gibi bir işlev, dizinin ilk elemanını bir **kopya olarak değil,
kendisi olarak** döndürebilir — çağıran `ilki(d) = Nokta{0, 0};` yazarak dizinin ilk
elemanını doğrudan değiştirebilir, çünkü dönüş değeri `d[0]`'ın kendisidir. Bu ders
dönüş değeri referansı koşturmaz (bu, `operator[]` gibi bindirilmiş işleçlerin tipik
kullanım biçimidir ve K05'te işlenir), ama parametre referanslarıyla aynı ilkeye
dayanır: bir referans döndürmek, yeni bir nesne kurmadan var olan bir nesneye erişim
vermektir.

## Referans Argümanlar Üye İşlevlerde

Bu ilke üye işlevler için de aynı biçimde işler. Beşinci dersteki `Tampon::operator=`
imzası `Tampon& operator=(const Tampon& digeri)` idi — `digeri` parametresi burada da
çağıranın kendi nesnesidir, `b = a;` yazıldığında `operator=`'in içindeki `digeri`, `a`
ile aynı adrestir. `operator=`'in `digeri.veri_`'yi okuduğu her satır, doğrudan `a`'nın
belleğini okur; eğer `digeri` değerle alınsaydı (`Tampon digeri` olarak), her `b = a;`
çağrısı önce bir `Tampon` kopyası kurar, `operator=` bu kopyayla çalışırdı — bu hem
gereksiz bir kopyalayan yapıcı çağrısı hem gereksiz bir yıkıcı çağrısı demektir. `const
Tampon&` seçimi burada da aynı niyeti taşır: `a`'yı kopyasız oku, değiştirme.

## Referans Yeniden Bağlanamaz

Bir işaretçi kurulduktan sonra başka bir nesneyi göstermek üzere değiştirilebilir:
`ptr = &baska;`. Bir referans için bu mümkün değildir — `Nokta& r = p;` yazıldıktan sonra
`r = baska;` bir yeniden bağlama değildir, `baska`nın değerini `r`'nin (yani `p`'nin)
üzerine **atar**. Referans kurulduğu anda hangi nesneye bağlı olacağı sabitlenir ve bu bağ
referansın ömrü boyunca değişmez — bu yüzden bir referans **kurulurken** ilklendirilmek
zorundadır, boş bir referans (işaretçinin `nullptr`'ı gibi) yoktur.

## const Referansın Geçiciye Bağlanması

```cpp
// gecici-baglama-olcumu.cpp — const referans geciciye baglanabiliyor mu
#include <cstdio>

#include "nokta.hpp"

void yaz(const Nokta& n) {
    std::printf("yaz icinde x=%d y=%d\n", n.x, n.y);
}

int main() {
    Nokta p{1, 2};
    yaz(p);

    const Nokta& r = Nokta{3, 4};
    std::printf("gecici uzerinden x=%d y=%d\n", r.x, r.y);

    yaz(Nokta{5, 6});
    return 0;
}
```

```text
yaz icinde x=1 y=2
gecici uzerinden x=3 y=4
yaz icinde x=5 y=6
```

**SK13.** `const Nokta& r = Nokta{3, 4};` satırı bir **geçici** nesneye (`Nokta{3, 4}`, adı
olmayan, ifadenin ortasında kurulan bir değer) `const` bir referans bağlar. Normalde bir
geçicinin ömrü onu kuran ifadenin sonunda biter, ama bir `const` referansa bağlandığında
C++ standardı bu geçicinin ömrünü referansın ömrüne kadar **uzatır** — `r` geçerli olduğu
sürece `Nokta{3, 4}` de geçerlidir, bu yüzden `r.x` ve `r.y` okumaları tanımsız davranış
değildir. Aynı bağlama `Nokta& r = Nokta{3, 4};` (const olmadan) yazılsaydı derlenmezdi:
sıradan bir referans bir geçiciye bağlanamaz, çünkü geçici üzerinde yazma yapılabilir
olması (`r.x = 99;` gibi) çağıranın hiç göremeyeceği, hemen sonra yok olacak bir nesneyi
değiştirmek anlamına gelirdi — dil bunu anlamsız bularak baştan engeller. `yaz(Nokta{5,
6})` çağrısı da aynı kuralı kullanır: `yaz`'ın parametresi `const Nokta&` olduğu için
geçici doğrudan bağlanabilir, parametre sıradan `Nokta&` olsaydı bu çağrı derlenmezdi.

## Referans ve Bellek Düzeni

M11/K01'de bir yapının bellek düzeni — üye sırası, hizalama ve dolgu —
işlenmişti. Bir referans o dersteki anlamda "yeni bir bellek düzeni"
kurmaz — `Nokta& r = p;` yazıldığında `r`'nin kendi bir `sizeof` değeri ya da kendi bir
bellek düzeni yoktur, çünkü `r` yeni bir nesne değildir, `p`'nin başka bir adıdır. Bir
referans üyesi olan bir sınıf (`Nokta& referans_;` gibi bir üye) bu kuralın istisnası
gibi görünebilir — böyle bir üye genellikle bir işaretçi büyüklüğünde yer kaplar, çünkü
derleyici onu öyle koda çevirir — ama bu bir uygulama detayıdır, dilin kendisi referansın
"nerede" tutulduğunu tanımlamaz; yalnız hangi nesneye bağlı olduğunu tanımlar.

## Sınırlayıcı Ölçüm

Bu dersin ölçtüğü ifade **kendisi** sınıfındadır — ama yalnız bazı durumlarda. `const
Nokta&` alan bir parametre hem **kendisi** hem **geçici** olabilir; imzanın kendisi
hangisi olduğunu söylemez, yalnız çağrı anındaki argüman belirler.

```cpp
// kendisi-mi-gecici-mi.cpp — const referans parametresi hangi durumda hangisi
#include <cstdio>

#include "nokta.hpp"

void yaz(const Nokta& n) {
    std::printf("yaz icinde x=%d y=%d\n", n.x, n.y);
}

int main() {
    Nokta p{7, 8};

    yaz(p);
    yaz(Nokta{9, 10});

    std::printf("p degismedi mi %s\n", (p.x == 7 && p.y == 8) ? "evet" : "hayir");
    return 0;
}
```

```text
yaz icinde x=7 y=8
yaz icinde x=9 y=10
p degismedi mi evet
```

**SK14.** `yaz(p)` çağrısında `n`, `p`'nin kendisidir — **kendisi** sınıfı; `yaz(Nokta{9,
10})` çağrısında ise `n`, ifadenin ortasında kurulan adsız bir geçiciye bağlıdır —
**geçici** sınıfı. İki çağrı da aynı imzayı (`const Nokta&`) kullanır, aynı işlevi
çağırır, ama parametrenin hangi sınıfa girdiği yalnız çağrı anındaki argümanın
kendisiyle belirlenir. `const` olması bu iki durumda da işlevin `n` üzerinden yazma
yapmasını engeller — bu yüzden `p` üçüncü satırda değişmeden kalır, `yaz` çağrısının `n`
kendisi mi geçici mi olduğunun `p`'nin durumu üzerinde hiçbir etkisi yoktur. Bir işlev
imzasına bakarak "bu parametre kendisi mi" sorusuna kesin cevap vermek mümkün değildir —
imza yalnız **değiştirilebilir mi** sorusuna (referans mı const referans mı) cevap verir;
kendisi mi geçici mi sorusunun cevabı her çağrıda yeniden belirlenir.

Bu sınır, sınıf tasarlarken düşünülmesi gereken bir sonuç doğurur: bir işlevin `const
Nokta&` parametresi kabul ettiğini görmek, o işlevin her zaman kalıcı bir nesneyle
çağrılacağını garanti etmez. İşlev gövdesi, aldığı referansın ömrünün çağrı ifadesinin
sonunda bitebileceğini varsaymalıdır — örneğin `n`'nin adresini bir yere saklayıp işlev
döndükten sonra kullanmak (`Nokta* p = &n; return p;` gibi), `n` bir geçiciye bağlıysa
sarkan bir işaretçi (dangling pointer) üretir. Bu ders böyle bir kodu koşturmaz; yalnız
sınırı belirtir. Bir sonraki dersteki `operator+`'ın neden bir referans değil **yeni bir
nesne** döndürdüğü de aynı sınırdan gelir: işlecin ürettiği toplam, işlecin kendi
gövdesinde kurulan yerel bir değerdir, işlev döndükten sonra da yaşaması gerekiyorsa
referansla değil, değerle döndürülmelidir.

## Özet

- Bir referans var olan bir nesneye verilen ikinci bir addır; yeni bir nesne kurmaz,
  yeni bir adres almaz.
- Referansla alınan bir argüman çağıranın **kendisi**dir — hiçbir kopyalama
  adımı çalışmaz, `&n == &p` doğrudur.
- Değer, referans ve const referans arasındaki seçim niyeti kodlar: kopyala-ve-dokunma,
  değiştir, ya da kopyasız-oku-ama-değiştirme.
- Bir referans kurulduktan sonra başka bir nesneye yeniden bağlanamaz.
- `const` bir referans bir geçiciye bağlanabilir (geçicinin ömrü uzar); sıradan bir
  referans bağlanamaz.
- `const Nokta&` alan bir parametre çağrıya göre hem **kendisi** hem **geçici**
  olabilir; imza tek başına bunu söylemez.

## Sonraki Adım

Bu ders bir referansın kopyasız, doğrudan çağıranın nesnesiyle çalıştığını ölçtü; bir
sonraki ve son ders bir işlecin (`operator+`) neden yeni bir **geçici** döndürdüğünü, ve
`operator+=`'in neden bunun yerine `*this`'i referansla döndürdüğünü ölçer.
