Parametreler ile Argümanlar
Bir fonksiyonun parametreleri, tanımındaki adlandırılmış değişkenlerdir; argümanlar ise fonksiyonu çağırırken ona verdiğiniz gerçek değerlerdir. Önceki sayfa fonksiyonların nasıl tanımlanıp çağrıldığını gösterdi; bu sayfa ise bu değerlerin aslında içeri nasıl girdiğiyle ilgili, çünkü C++ size birkaç yol sunar ve bu seçim hem doğruluğu hem de hızı etkiler.
C++'ta varsayılan değerle aktarmadır: fonksiyon bir kopya alır.
addTen içinde n, score'dan ilklendirilmiş ayrı bir değişkendir. n'yi yeniden atamak yalnızca o kopyaya dokunur, bu yüzden score, main'e dönüldüğünde dokunulmamış kalır. Bu güvenli ve öngörülebilirdir - fonksiyon verilerinizi kazara ezemez - işte tam da bu yüzden varsayılan budur.
Referansla Aktarma: Bir Fonksiyonun Çağıranı Değiştirmesine İzin Vermek
Bazen fonksiyonun çağıranın değişkenini değiştirmesini istersiniz. Parametre tipine bir & ekleyin, o bir referansa dönüşür - kopya değil, orijinalin bir takma adı:
İlk örnekten tek farkı &'tir, ama artık n ve score aynı nesnedir. Bu, birden fazla değer "döndürmenin" veya bir şeyi yerinde güncellemenin standart yoludur. Klasik bir kullanım iki değişkenin yerini değiştirmektir:
& olmadan, swapValues iki kopyayı karıştırır ve main hiçbir değişiklik görmezdi - çok yaygın bir acemi hatası.
Const Referanslar: Ucuz, Salt-Okunur Erişim
Değerle aktarma argümanı kopyalar. Bir int için bunun maliyeti yoktur, ancak her çağrıda büyük bir string veya vector kopyalamak gerçek ve boşa giden bir iştir. Çözüm bir const referanstır (const T&): kopya olmadan referans hızını, artı argümanı değiştirmeyeceğine dair derleyici tarafından zorunlu kılınan bir sözü elde edersiniz.
Pratik bir genel kural: küçük yerleşik tipleri (int, double, char, bool, işaretçiler) değerle aktarın ve yalnızca okumanız gereken büyük nesneleri const referansla aktarın. Düz, const olmayan bir T&'yi, çağıranın nesnesini gerçekten değiştirmeyi amaçladığınız durumlar için saklayın.
İnce bir tuzak: düz bir int& n, geçici bir nesneye veya bir sabit değere bağlanamaz. İlk örnekteki addTen(5), parametre int& olsaydı derlenmezdi, çünkü 5 takma adını verebileceğiniz bir değişken değildir. Bir const int& ise 5'e bağlanabilir, ki bu da const referansların neden bu kadar yaygın kullanıldığının bir başka nedenidir.
Varsayılan Argümanlar
Bir parametreye yedek bir değer verebilirsiniz, böylece çağıranlar onu atlayabilir. Argüman eksikse varsayılan değer kullanılır:
İki kural insanların ayağını kaydırır. Birincisi, varsayılanlar sonda olmalıdır - bir parametrenin varsayılanı olduğunda ondan sonraki her parametrenin de olması gerekir. void f(int a = 1, int b) yazamazsınız çünkü a'yı atlayıp b'yi vermenin bir yolu olmazdı. İkincisi, bir fonksiyon bir başlık dosyasında bildirilip başka bir yerde tanımlandığında, varsayılanı yalnızca bildirime koyun, asla tanımda tekrarlamayın - tekrarlamak bir derleme hatasıdır.
Dizileri ve Vektörleri Aktarma
Ham bir dizi aktarıldığında bir işaretçiye bozulur, bu yüzden fonksiyon dizinin boyutunu kaybeder - neredeyse her zaman uzunluğu yanında aktarırsınız:
Dizi bir işaretçiye dönüştüğü için, sum içinde sizeof(arr) dizinin değil bir işaretçinin boyutunu verir - kötü şöhretli bir hata. Modern C++'ta, kendi boyutunu taşıyan ve const referansla aktarılan bir std::vector (veya C++20'de bir std::span) tercih edin:
const&'e dikkat edin: onu kaldırın ve her çağrı tüm vektörü kopyalar. Dört elemanlı bir vektör için bu zararsızdır, ama bir milyon eleman için sessiz bir performans çukurudur.
İşaretçi Parametreleri
Bir işaretçi (T*) de aktarabilirsiniz. Bir referans gibi bu da fonksiyonun çağıranın verisine ulaşmasını sağlar, ancak bir işaretçi yeniden konumlandırılabilir veya null olabilir - bu yüzden "değer yok" meşru bir seçenek olduğunda doğru araçtır:
Çağıran, adresini paylaşmak için &value aktarır ve fonksiyon *out üzerinden yazar. Referanslardan temel farkı: bir işaretçi nullptr olabilir, bu yüzden bir işaretçi alan fonksiyon, içeriğine erişmeden önce kontrol etmelidir - bu korumayı atlayıp null bir işaretçinin içeriğine erişmek tanımsız davranıştır, genellikle bir çökme. "Değer yok" hiçbir zaman anlamlı değilse, bir referans daha temizdir çünkü en başından null olamaz.
Sıradaki: Referanslar
Parametreler, referansların ekmeğini kazandığı yerdir, ama referanslar başlı başına bir özelliktir - yalnızca bir fonksiyon imzasının içinde değil, herhangi bir değişken için oluşturabileceğiniz takma adlar. Sıradaki sayfa referansların kendi başlarına nasıl çalıştığını derinlemesine ele alıyor: bunları nasıl bildireceğiniz, neden hemen ilklendirilmeleri gerektiği, bir lvalue referansı ile bir const referans arasındaki fark ve bir referansın nasıl ince yollarla sarkar (dangling) hâle gelebileceği.
Sıkça Sorulan Sorular
C++'ta değerle aktarma ile referansla aktarma arasındaki fark nedir?
Değerle aktarma argümanı parametreye kopyalar, bu yüzden fonksiyon içindeki değişiklikler çağıranı etkilemez. Referansla aktarma (int&) parametreyi çağıranın değişkeninin bir takma adı yapar, bu yüzden değişiklikler dışarıdan görülür. Kopyalamak için void f(int x), orijinali değiştirmek için void f(int& x) kullanın.
C++'ta const referans parametresini ne zaman kullanmalısınız?
Büyük bir nesneyi kopyalamadan ve fonksiyonun onu değiştirmesine izin vermeden okumak istediğinizde const T& kullanın - örneğin void print(const string& s). Size referansla aktarmanın hızını, değerle aktarmanın güvenliğiyle birlikte verir. int veya char gibi küçük tipler için düz değerle aktarma da aynı derecede hızlıdır.
C++'ta varsayılan argümanlar nedir?
Varsayılan argümanlar, çağıran kişi bir parametreyi atladığında parametrenin yedek bir değer almasını sağlar, ör. void greet(string name = "there"). Varsayılanlar sondaki (en sağdaki) parametreler olmalıdır ve bunları yalnızca bildirimde belirtirsiniz; ikisi ayrıysa tanımda belirtmezsiniz.