---
title: 'İşleç Aşırı Yükleme'
source: 'https://academia.sh/tr/kurslar/cpp-temelleri/islec-asiri-yukleme'
course: 'C++ Temelleri ve Nesne Tasarımı'
language: tr
updated: '2026-09-26T03:02:45+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - "operator+'nın yeni bir geçici nesne döndürdüğünü ölçer"
    - "operator+='in kendi nesnesini değiştirip referansla döndürdüğünü ayırt eder"
    - 'Bir sınıf için hangi işleçlerin anlamlı olduğuna karar verirken sınırları uygular'
---

# İşleç Aşırı Yükleme

operator+'nın neden yeni bir geçici nesne döndürdüğünü, operator+='in neden bunun yerine kendi nesnesini referansla döndürdüğünü ölçer.

Bu, K04'ün bu bölümdeki son dersidir. Önceki ders bir referansın hiçbir kopya üretmeden
çağıranın kendi nesnesiyle çalıştığını ölçtü. Bu ders, bir **işlecin** (operator) bazen
tam tersini yaptığını — yeni bir nesne ürettiğini — ölçer. Ölçüm sınıfı **geçici**:
`a + b` ifadesinin sonucu, ne `a` ne `b`'dir; işlecin gövdesinde kurulan, ifadenin sonunda
yok olan yeni bir `Para` nesnesidir.

C'de böyle bir toplamanın tek yolu adı açık bir işlevdi: `Para toplama_yap(Para a, Para
b)` gibi bir işlev çağrılır, sonucu ayrı bir değişkene atanırdı — `a + b` yazmak mümkün
değildi, çünkü `+` yalnız yerleşik sayısal tipler için tanımlıydı. C++'ta `operator+`
aşırı yüklemesi, `Para` gibi kullanıcı tanımlı bir tip için de `+` sözdizimini kullanıma
açar; çağıran taraf `toplama_yap(a, b)` yerine `a + b` yazar. Bu, sözdiziminin okunurluğunu
artırır, ama gövdenin ne yaptığını (yeni bir nesne mi kurduğunu, var olan bir nesneyi mi
değiştirdiğini) gizler de — bu yüzden bu dersin ölçümü tam olarak bunu, işlecin
sözdiziminin arkasında hangi nesnenin üretildiğini, açığa çıkarır.

## İşleç Aşırı Yükleme Nedir

**İşleç aşırı yükleme** (operator overloading), `+`, `==`, `<<` gibi yerleşik işleçlerin
kullanıcı tanımlı bir sınıf için ne anlama geldiğini tanımlamaktır. `operator+` bir üye
işlev olarak yazıldığında, `a + b` ifadesi derleyici tarafından `a.operator+(b)` olarak
okunur — sözdizimi `+` kalır, ama çağrılan şey sınıfın kendi yazdığı bir işlevdir.
Aşırı yükleme yeni bir sözdizimi eklemez; var olan işleç sözdizimini kullanıcı tanımlı
tipler için **anlamlandırır**.

Aşırı yükleme bir işlecin **kaç argüman** aldığını ya da **öncelik sırasını**
değiştiremez — `+` her zaman ikili kalır, `*`'ten sonra değerlendirilmeye devam eder.
Değişebilen tek şey işlecin argümanları için ne yaptığıdır. Bu sınır kasıtlıdır:
`operator+`'yı çağıran biri, `Para` için de tıpkı `int` için olduğu gibi "iki değeri alıp
bir sonuç üretir" davranışını bekler; aşırı yükleme bu beklentiyi bozacak bir sözdizimi
değişikliği yapamaz, yalnız "sonuç" ve "değiştirme" kısmının ne anlama geldiğini
tanımlayabilir.

```cpp
// para.hpp — kurus cinsinden tutar tutan, islec asiri yuklemesi icin bir sinif
#ifndef PARA_HPP
#define PARA_HPP

#include <cstdio>

class Para {
public:
    explicit Para(long kurus) : kurus_(kurus) {}

    Para operator+(const Para& digeri) const {
        return Para(kurus_ + digeri.kurus_);
    }

    Para& operator+=(const Para& digeri) {
        kurus_ += digeri.kurus_;
        return *this;
    }

    bool operator==(const Para& digeri) const {
        return kurus_ == digeri.kurus_;
    }

    long kurus() const { return kurus_; }

private:
    long kurus_;
};

inline void yaz_para(const Para& p) {
    std::printf("kurus=%ld\n", p.kurus());
}

#endif
```

## `operator+`: Yeni Bir Geçici Döndürür

```cpp
// artı-olcumu.cpp — a + b sonucu yeni bir gecici mi
#include <cstdio>

#include "para.hpp"

int main() {
    Para a(100);
    Para b(250);

    Para c = a + b;

    std::printf("c ile a ayni nesne mi %s\n", &c == &a ? "evet" : "hayir");
    std::printf("c ile b ayni nesne mi %s\n", &c == &b ? "evet" : "hayir");
    yaz_para(a);
    yaz_para(b);
    yaz_para(c);
    return 0;
}
```

```text
c ile a ayni nesne mi hayir
c ile b ayni nesne mi hayir
kurus=100
kurus=250
kurus=350
```

**SK15.** `a + b` ifadesi `a.operator+(b)` çağrısına dönüşür; `operator+`'nın gövdesi
`return Para(kurus_ + digeri.kurus_);` ile **yeni** bir `Para` kurar ve bunu **değerle**
döndürür — `a`'yı da `b`'yi de değiştirmez, ikisi de kendi `kurus_` değerini korur (`100`
ve `250`). Döndürülen nesne `c`'ye kurulur; `c`'nin adresi ne `a`'nınkiyle ne `b`'ninkiyle
aynıdır. `operator+`'nın `const` işaretli olması (`operator+(const Para& digeri) const`)
hem `digeri`'nin hem çağrıldığı nesnenin (`this`) değiştirilmediğini garanti eder — bir
toplama işleci, tanım gereği, toplananları değil yalnız sonucu üretmelidir.

## `operator+=`: Kendi Nesnesini Değiştirip Referansla Döner

```cpp
// arti-esittir-olcumu.cpp — a += b, a'nin kendisini mi degistiriyor
#include <cstdio>

#include "para.hpp"

int main() {
    Para a(100);
    Para b(250);

    Para& sonuc = (a += b);

    std::printf("sonuc ile a ayni nesne mi %s\n", &sonuc == &a ? "evet" : "hayir");
    yaz_para(a);
    return 0;
}
```

```text
sonuc ile a ayni nesne mi evet
kurus=350
```

**SK16.** `operator+=`'in gövdesi `kurus_ += digeri.kurus_;` ile **kendi** `kurus_`
üyesini değiştirir, sonra `return *this;` ile **kendisini** referansla döndürür — yeni bir
nesne kurmaz. `a += b` çağrıldığında `a`'nın kendisi değişir (`350` olur) ve
`(a += b)`'nin sonucu da yine `a`'nın kendisidir: `&sonuc == &a` doğrudur. Bu, `operator+`
ile taban tabana zıttır: `operator+` iki toplananı da değiştirmeden yeni bir **geçici**
üretirken, `operator+=` tek bir nesneyi (soldaki) değiştirip **kendisi** sınıfında bir
referans döner. İki işlecin dönüş tipi bu farkı imzada taşır — `operator+` değerle
(`Para`), `operator+=` referansla (`Para&`) döner; imza okunarak hangisinin yeni bir
nesne ürettiği, hangisinin var olan bir nesneyi değiştirdiği önceden bilinebilir.

## Anlamlı İşleç Tanımlamanın Sınırları

Bir işlecin kullanıcı tanımlı bir sınıf için aşırı yüklenebiliyor olması, her sınıfın her
işleci tanımlaması gerektiği anlamına gelmez. Birkaç yerleşik kural işleç tanımlarını
tutarlı tutar:

- **`+`, `-`, `*` gibi ikili aritmetik işleçler** genellikle üye değil **serbest işlev**
  (free function) olarak yazılır (`Para operator+(const Para& a, const Para& b)`), çünkü
  bu, sol tarafı `Para` olmayan ifadelerde de (örneğin gelecekte bir `int` ile `Para`
  toplanacaksa) simetrik dönüşüm sağlar. `Para` bu dersin ölçümü için `operator+`'yı üye
  olarak tanımlar; serbest işlev biçimi yalnız burada anılır.
- **`+`, `+=` üzerinden yazılabilir**: `operator+`'nın gövdesi `kurus_ + digeri.kurus_`
  yerine `Para sonuc(kurus_); sonuc += digeri; return sonuc;` biçiminde de yazılabilirdi
  — `+=`'in mantığını tekrar etmeden `+`'yı ona dayandırmak, iki işlecin davranışının
  birbirinden sapmasını engeller. `Para` bu dersin ölçümünü sade tutmak için ikisini
  bağımsız yazar.
- **`==` bir eşitlik**, bir sıralama değildir; `Para::operator==` iki nesnenin `kurus_`
  değerlerini karşılaştırır, `<` gibi bir sıralama işleci bu derste tanımlanmaz.
- **`<<` (akış çıktısı) bir üye işlev olamaz** — `std::cout << p` ifadesinde sol taraf
  `std::ostream`dur, `Para` değil; bu yüzden `operator<<` bir serbest işlev olarak
  yazılır ve `Para`'nın `private` üyesine erişmesi gerekiyorsa `friend` bildirimiyle
  (ikinci derste yalnız adıyla anılmıştı) izin verilir. Bu ders `operator<<` tanımlamaz,
  `yaz_para` adında sıradan bir işlevle aynı işi görür.

Bir işleci aşırı yüklerken sorulması gereken soru şudur: bu işlecin yerleşik anlamı
(`+` toplar, `==` karşılaştırır, `<<` yazdırır) sınıf için hâlâ **doğal** mı? `Para` için
`+` toplamı, `==` eşitliği anlamlı biçimde karşılar; ama örneğin `Para operator*(const
Para& a, const Para& b)` iki tutarı çarpmanın parasal bir anlamı olmadığı için tanımsız
bırakılabilirdi — bu ders böyle bir işleç yazmaz.

Bu sınırın ihlali derlenir ama okunmaz kılar. C++ hiçbir işlecin hangi anlamda
kullanılacağını zorlamaz — `operator+`'nın gövdesine teknik olarak bir çıkarma yazılabilir,
derleyici buna itiraz etmez. Ama böyle bir kod, `a + b` yazan herkesin beklediği
("toplanıyor") ile gerçekte olanı ("çıkarılıyor") ayırır — bu, sınıfın kullanıcısını
yanıltan, hatası derleme zamanında yakalanamayan bir tasarım kusurudur. Aşırı yükleme
gücünü kısıtlayan tek şey derleyici değil, işlecin okuyucuda uyandırdığı beklentiye sadık
kalma disiplinidir.

## `explicit`, Kopyalayan Yapıcı ve İşleçlerin Buluştuğu Yer

`Para`'nın yapıcısı `explicit Para(long kurus)` olarak tanımlıdır — üçüncü dersteki
`explicit` kuralı burada da geçerlidir: `Para p = 100;` gibi örtük bir dönüşüm derlenmez,
`Para p(100);` ya da `Para p{100};` yazılmalıdır. Bu, işleç aşırı yüklemesiyle doğrudan
etkileşir: `operator+`'nın gövdesindeki `return Para(kurus_ + digeri.kurus_);` satırı
**açık** bir kurma yazar; eğer yapıcı `explicit` olmasaydı ve gövde yalnız `return kurus_ +
digeri.kurus_;` yazsaydı, `long` sonucu örtük olarak bir `Para`'ya dönüştürülebilirdi —
bu, üçüncü dersin uyardığı türden, istenmeyen bir örtük dönüşüm zincirine kapı açardı
(örneğin bir `Para`'nın yanlışlıkla bir `long`la, dolaylı yoldan, karşılaştırılabilmesi
gibi). `operator+`'nın sonucu her zaman açıkça bir `Para` kurarak döndürülür; bu hem
`explicit` kuralına uyar hem işlecin ne ürettiğini kod içinde açık tutar. Beşinci dersteki
kopyalayan yapıcı da burada örtük olarak devreye girer: `return Para(...)` satırı yeni bir
`Para` değeri döndürdüğünde, derleyici çoğu durumda bu değeri doğrudan çağıranın alacağı
yere kurar (değer kopyalamayı atlayan bir optimizasyon), ama kavramsal model hâlâ "yeni bir
nesne kuruldu ve döndürüldü"dür — kopyalayan yapıcının hiç çağrılmaması bir optimizasyon
ayrıntısıdır, `operator+`'nın yeni bir nesne ürettiği gerçeğini değiştirmez.

## Değer Semantiği: Bu Kursun Bağlamı

M11/K01'de bir yapının atamayla bütün alanlarıyla kopyalandığı görülmüştü; bu, değer
semantiğidir (value semantics): bir değer atandığında ya da aktarıldığında, iki taraf birbirinden bağımsız hâle gelir. `Para`
bu ilkeyi C++'ın kendi araçlarıyla — kopyalayan yapıcı, kopyalayan atama, ve şimdi
`operator+`'nın yeni bir değer döndürmesiyle — uygular. `operator+=` ise kasıtlı olarak
bu ilkenin dışına çıkar: kendi nesnesini değiştirir, çünkü `+=`'in yerleşik anlamı zaten
"soldaki değeri güncelle"dir (`x += 1` de `x`'i değiştirir, yeni bir değişken kurmaz).
Bir sınıf için işleç yazarken bu iki davranış biçiminden hangisinin seçildiği, işlecin
yerleşik `int`/`long` karşılığının davranışıyla tutarlı olmalıdır — `Para` bu tutarlılığı
korur: `+` yeni bir değer üretir, `+=` var olanı değiştirir, tıpkı `int` için olduğu gibi.

## Kopya, Geçici ve Kendisi Ayrımının Özeti

Bu konunun yedi dersi tek bir soruyu farklı açılardan ölçtü: bir ifade **hangi nesneyle**
çalışıyor? Üçüncü ve dördüncü dersler bir nesnenin kendi kaynağını nasıl aldığını (yapıcı,
yıkıcı, RAII); beşinci ders bir kopyanın orijinalinden nasıl ayrıştığını (**kopya**);
altıncı ders bir referansın hiç kopyalamadan çağıranın **kendisi**yle nasıl çalıştığını;
bu ders ise bir işlecin ne zaman yeni bir **geçici** ürettiğini, ne zaman kendi nesnesini
değiştirip **kendisi**ni döndürdüğünü ölçtü. Dört sınıf — **kendisi**, **kopya**,
**parça**, **geçici** — bir C++ ifadesini okurken sorulacak tek soruya karşılık gelir:
bu ifadenin ürettiği ya da işlediği nesne, başka hangi nesneyle aynı, ve hangisinden
farklı?

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

```cpp
// zincirleme-olcumu.cpp — a + b + c kac gecici uretir
#include <cstdio>

#include "para.hpp"

int main() {
    Para a(10);
    Para b(20);
    Para c(30);

    Para toplam = a + b + c;

    yaz_para(toplam);
    return 0;
}
```

```text
kurus=60
```

**SK17.** `a + b + c` ifadesi soldan sağa değerlendirilir: önce `a + b` çalışır ve
`kurus_=30` değerinde adsız bir `Para` üretir; sonra bu sonuç `+ c` çağrısının sol tarafı
olur. `operator+` bir üye işlev olduğu için ikinci çağrının `this`'i bir nesneyi göstermek
zorundadır: `a + b`'nin sonucu bu yüzden **bir geçici** olarak kurulur ve tam ifade
(`a + b + c;`nin sonu, noktalı virgül) bitene kadar yaşar, sonra yıkılır. İkinci
`operator+` çağrısının `kurus_=60` değerindeki sonucu ise ayrı bir geçici olarak
kurulmaz: C++17'nin garantili kopya seçimi (guaranteed copy elision) gereği doğrudan
`toplam`ın kendi deposunda kurulur. İki `operator+` çağrısı, dolayısıyla **bir** geçici;
`toplam` ikinci çağrının sonucunun ta kendisidir, bir kopyası değil. `Para`'nın yıkıcısı
burada bir `printf` içermediği için geçicinin kurulma ve yıkılma anı bu blokta
gözlemlenmiyor; sayı dilin kuralından okunur, bu ölçümden değil. Zincirleme bir
toplamanın "kaç geçici ürettiği" sorusunun cevabı, işlecin kaç kez çağrıldığından çok,
her sonucun nereye gittiğine bağlıdır: bir sonraki çağrının nesnesi olan ara sonuç
geçicidir, bir değişkeni ilklendiren son sonuç o değişkenin kendisidir.

## Özet

- Bu dersin ölçtüğü ifade **geçici** sınıfındadır: `operator+` toplananları değiştirmeden
  yeni ve adsız bir `Para` döndürür; dönüş tipi değerledir (`Para`, referans değil).
- `operator+=` kendi nesnesini değiştirir ve **kendisini** (`*this`) referansla
  döndürür; dönüş tipi `Para&`dır.
- İkili aritmetik işleçler genellikle serbest işlev olarak yazılır; `<<` bir üye işlev
  olamaz çünkü sol tarafı sınıfın kendisi değildir.
- Bir işleç yalnız yerleşik anlamı sınıf için doğal olduğunda tanımlanmalıdır.
- Zincirleme bir ifadede (`a + b + c`) yalnız ara sonuç (`a + b`) geçici olarak kurulur
  ve tam ifade bitene kadar yaşar; son sonuç doğrudan `toplam`ın içinde kurulur.
- Bu konunun yedi dersi aynı soruyu sordu: bir C++ ifadesi **kendisi**, **kopya**,
  **parça** ya da **geçici** nesnelerden hangisiyle çalışıyor?

## Sonraki Adım

Bu konu, bir nesnenin kendi kaynağını nasıl aldığını, kopyalandığını, referansla
aktarıldığını ve işleçler aracılığıyla yeni nesneler ürettiğini ölçtü. Bir sonraki konu
bu tek nesne modelinden uzaklaşıp sınıflar arasındaki **ilişkiye** — bir sınıfın başka
bir sınıfın davranışını nasıl genişlettiğine ve çalışma zamanında hangi işlevin
çağrılacağının nasıl belirlendiğine — geçer.
