Anasayfa / C++ / C++ Fonksiyonlar

C++ Fonksiyonlar

Yazılım geliştirme sürecinde, karmaşık ve büyük bir problemi çözmek için programı daha küçük, yönetilebilir parçalara bölmek en temel mühendislik prensiplerinden biridir. Yukarıdan aşağıya (top-down) ve yapısal programlamanın en önemli araçlarından biri olan fonksiyonlar, C++ programlarının temel yapı taşlarını oluşturur.

Bir programda belirli bir işlemi gerçekleştiren kod bloğunu fonksiyon içine almanın en büyük avantajı, program boyutunu küçültmek ve kodu farklı yerlerde tekrar tekrar kullanabilmektir (reusability). C++ dili, nesne yönelimli programlama (OOP) yeteneklerini desteklemek için klasik C fonksiyonlarına birçok yeni, güçlü ve esnek özellik (aşırı yükleme, varsayılan argümanlar, satıriçi fonksiyonlar vb.) eklemiştir.

Bu kapsamlı rehberde, C++’ta fonksiyonların nasıl tanımlandığını, parametre geçiş yöntemlerini ve modern C++ fonksiyon özelliklerini detaylı örneklerle inceleyeceğiz.

1. Temel Yapı ve main() Fonksiyonu

C programlama dilinde main() fonksiyonu herhangi bir dönüş tipi belirtilmeden yazılabilirken, C++ dilinde main() fonksiyonu işletim sistemine int tipinde bir değer döndürmek zorundadır.

Bir değer döndürmesi gereken fonksiyonlar return ifadesi ile sonlanmalıdır. Bu nedenle modern C++ standartlarında main() fonksiyonu her zaman int main() olarak tanımlanır ve programın sonunda işletim sistemine sıfır (0) değeri döndürülür. Sıfır değeri, işletim sistemine programın hatasız ve başarılı bir şekilde çalışıp sonlandığını bildirir; sıfır dışındaki bir değer ise bir sorun veya hata olduğunu gösterir.

#include <iostream>
using namespace std;

int main() {
    cout << "C++ programi basariyla calisiyor." << endl;
    return 0; // İşletim sistemine başarılı kapanış bildirimi
}

2. Fonksiyon Prototipleme (Function Prototyping)

C++ diline eklenen en önemli iyileştirmelerden biri fonksiyon prototiplemesidir (Function Prototyping). Prototip, derleyiciye fonksiyonun arayüzünü (interface) tanıtır: fonksiyonun kaç tane ve ne tipte argüman alacağını ve hangi tipte bir değer döndüreceğini belirtir.

C++’ta bir fonksiyonu çağırmadan önce onun prototipini bildirmek zorunludur (klasik ANSI C’de bu işlem isteğe bağlıydı). Derleyici, fonksiyon çağrıldığında bu şablonu (prototipi) kullanarak gönderilen argümanların ve dönüş tipinin doğru olup olmadığını kontrol eder. Herhangi bir uyumsuzluk derleme aşamasında (compile-time) yakalanır.

Sözdizimi (Syntax): donus_tipi fonksiyon_adi (argüman_listesi);

Örnek:

float hacimHesapla(int x, float y, float z); // Prototip bildirimi

Fonksiyon bildiriminde argümanların isimlerini yazmak isteğe bağlıdır, sadece veri tiplerini (örneğin float hacimHesapla(int, float, float);) belirtmek derleyici için yeterlidir. Ancak fonksiyonun asıl gövdesinin yazıldığı “tanımlama” (definition) kısmında değişken isimleri mutlaka verilmelidir.

3. Referans ile Çağırma (Call by Reference)

Geleneksel C dilinde bir fonksiyona parametre gönderildiğinde “değer ile çağırma” (call by value) yöntemi kullanılır. Bu yöntemde çağrılan fonksiyon, argümanların yeni bir kopyasını oluşturur ve sadece bu kopyalar üzerinde çalışır; dolayısıyla orijinal değişkenlerin değeri değiştirilemez. Ancak “Bubble Sort” gibi sıralama veya yer değiştirme (takas) işlemlerinde, fonksiyonun çağıran programdaki orijinal değişkenleri doğrudan değiştirebilmesi gerekir.

C++’ın sunduğu referans değişkenleri (reference variables) sayesinde, argümanları referans olarak fonksiyona aktarabiliriz (Call by Reference). Bu yöntemde formal argümanlar, orijinal argümanların kopyası değil, doğrudan bir “takma adı” (alias) haline gelir.

Örnek: İki sayının yerini değiştiren Swap fonksiyonu

#include <iostream>
using namespace std;

// Argümanlar referans (&) olarak alınıyor
void takas(int &a, int &b) {
    int gecici = a;
    a = b;
    b = gecici;
}

int main() {
    int x = 15, y = 30;
    cout << "Takas oncesi: x=" << x << " y=" << y << endl;

    takas(x, y); // Referans ile çağrı

    cout << "Takas sonrasi: x=" << x << " y=" << y << endl;
    return 0;
}

Yukarıdaki kodda takas fonksiyonu &a ve &b referanslarını kullandığı için, takas(x, y) çağrıldığında a değişkeni x‘in, b değişkeni ise y‘nin bir alias’ı (takma adı) olur. Fonksiyon içinde a ve b değiştiğinde, doğrudan main fonksiyonundaki x ve y de değişmiş olur.

4. Satıriçi (Inline) Fonksiyonlar

Bir programda fonksiyon kullanmak bellek tasarrufu sağlar ancak fonksiyon her çağrıldığında sisteme ek bir yük (overhead) bindirir. Program; çağrılan fonksiyona dallanmak, parametreleri yığına (stack) kaydetmek ve fonksiyon bitince geri dönmek zorundadır. Çok küçük bir fonksiyon döngü içinde binlerce kez çağrılırsa, bu geçiş işlemleri fonksiyonun kendi işlevinden daha fazla zaman alabilir.

C++ bu sorunu çözmek için inline (satıriçi) fonksiyon özelliğini sunar. Bir fonksiyon inline olarak tanımlandığında, derleyici fonksiyon çağrısını doğrudan o fonksiyonun koduyla değiştirir (tıpkı makrolar gibi, ancak derleyici kontrolü altında ve güvenli bir şekilde).

#include <iostream>
using namespace std;

// Inline fonksiyon tanımı
inline float kupAl(float a) {
    return (a * a * a);
}

int main() {
    float sayi = 3.0;
    // Derleme aşamasında bu satır "sonuc = (3.0 * 3.0 * 3.0);" olarak değiştirilir
    float sonuc = kupAl(sayi);
    cout << "Sayinin kupu: " << sonuc << endl;
    return 0;
}

Satıriçi fonksiyonlar işlem hızını artırır (çünkü fonksiyon çağrısı maliyeti ortadan kalkar) ancak program belleğinde daha fazla yer kaplanmasına sebep olur; bu yüzden sadece bir-iki satırlık küçük fonksiyonlar için kullanılması tavsiye edilir.

5. Varsayılan Argümanlar (Default Arguments)

C++ dilinde, bir fonksiyonu tüm argümanlarını belirtmeden de çağırabilmemiz için Varsayılan Argümanlar (Default Arguments) özelliği bulunmaktadır. Fonksiyon bildirimi sırasında argümanlara atanan bu varsayılan değerler, fonksiyon çağrılırken o argüman eksik bırakıldığında otomatik olarak devreye girer.

Kural: Varsayılan değerler sadece sondaki (en sağdaki) argümanlara verilebilir, değer atamaları sağdan sola doğru yapılmalıdır.

Örnek:

// Vade ve faiz oranı (r) varsayılan değerlere sahiptir
float faizHesapla(float anapara, int vade, float r = 0.15);

// Kullanımlar:
faizHesapla(5000, 7);       // r argümanı eksik, varsayılan 0.15 kullanılır
faizHesapla(5000, 5, 0.12); // Eksik argüman yok, r için 0.12 kullanılır

6. Fonksiyon Aşırı Yükleme (Function Overloading)

Nesne yönelimli programlamanın “polimorfizm” (çok biçimlilik – tek isim, birden fazla form) özelliğinin en önemli yansımalarından biri Fonksiyon Aşırı Yüklemedir (Function Overloading),. C++’ta aynı isme sahip ancak aldığı argüman sayısı veya argüman tipi farklı olan birden fazla fonksiyon tanımlayabilirsiniz.

Derleyici, fonksiyon çağrıldığı zaman gönderilen argümanların tipine ve sayısına bakarak (dönüş tipine bakılmaz), yazılmış olan fonksiyonlardan en uygun olanını (best match) seçer ve onu çalıştırır,.

Örnek Kullanım:

#include <iostream>
using namespace std;

// Tam sayılar için küp hesaplama
int hacim(int s) {
    return (s * s * s);
}

// Silindir için hacim hesaplama
double hacim(double r, int h) {
    return (3.14159 * r * r * h);
}

// Dikdörtgen prizma için hacim hesaplama
long hacim(long l, int b, int h) {
    return (l * b * h);
}

int main() {
    cout << "Kup hacmi: " << hacim(10) << endl;             // 1. fonksiyonu kullanır
    cout << "Silindir hacmi: " << hacim(2.5, 8) << endl;    // 2. fonksiyonu kullanır
    cout << "Prizma hacmi: " << hacim(100L, 75, 15) << endl;// 3. fonksiyonu kullanır
    return 0;
}

Örnekte hacim isminde üç farklı fonksiyon tanımlanmıştır. Tek bir isimle farklı veri setleri üzerinde aynı amaca hizmet eden (hacim bulma) işlemler yapılabilmektedir. Aşırı yükleme (overloading) kavramı, kodun okunabilirliğini muazzam ölçüde artırır.

7. Sabit (Const) Argümanlar ve Matematik Kütüphanesi

Güvenilir bir kod yazmak için, fonksiyonların kendilerine referans veya işaretçi (pointer) yoluyla gönderilen argümanları kazara değiştirmesini engellemek isteyebiliriz. Bu durumlarda fonksiyon parametresi const olarak (Örn: int uzunluk(const string &s);) tanımlanır ve derleyiciye, argümanın sadece “salt okunur” olduğu garantisi verilir.

Son olarak, karmaşık matematiksel operasyonlar kendi fonksiyonlarınızı yazmak yerine C++’ın Standart Kütüphanesindeki matematik fonksiyonlarıyla çözülebilir. <cmath> başlık dosyasını (eski C’deki math.h) programınıza dahil ederek sin(), cos(), sqrt() (karekök), pow() (üs alma) ve ceil() (yukarı yuvarlama) gibi her biri double dönüş tipine sahip ve oldukça optimize edilmiş fonksiyonları doğrudan projelerinizde kullanabilirsiniz.

Özetle, C++’ta fonksiyonlar, nesne yönelimli mimarinin bel kemiğidir. Modüler yapıyı sağlayan referansla geçiş (&), işlem maliyetini düşüren inline optimizasyonları ve esneklik sağlayan aşırı yükleme (overloading) özellikleri, başlangıç seviyesinden en üst düzey projelere kadar hatasız ve verimli yazılımlar üretmenizi garanti altına alır.

Etiketlendi:

Cevap bırakın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir