Menu

C++ Fonksiyon Aşırı Yükleme: Aynı İsim, Farklı Parametreler

C++ fonksiyon aşırı yükleme, parametre listeleri farklı olduğu sürece birden fazla fonksiyonun tek bir ismi paylaşmasına izin verir. Aşırı yükleme çözümlemesinin doğru sürümü nasıl seçtiğini, neden dönüş tipinin tek başına yeterli olmadığını ve kaçınmanız gereken belirsizlik ile varsayılan argüman tuzaklarını öğrenin.

Bu sayfada çalıştırılabilir editörler var - düzenle, çalıştır ve sonucu anında gör.

Tek İsim, Birçok Sürüm

Çoğu zaman aynı işlemi farklı veri türleri için yapman gerekir: bir int yazdırmak, bir string yazdırmak, bir double yazdırmak. Bazı dillerde printInt, printString, printDouble uydurursun. C++ ise hepsine aynı ismi vermene izin verir ve onları parametrelerine göre ayırt eder. İşte bu fonksiyon aşırı yüklemedir.

Kural basit: birden fazla fonksiyon, parametre listeleri farklı olduğu sürece bir ismi paylaşabilir - parametre sayısı, tipleri veya sırası bakımından. Derleyici her çağrı noktasındaki argümanlara bakar ve senin için eşleşen sürümü seçer.

Üç fonksiyon, tek isim. Her çağrı, parametre tipi argümana uyan sürüme iner. std::cout << x ifadesinin int, double ve string'ler için aynı şekilde çalışmasını sağlayan şey budur - operator<< defalarca aşırı yüklenmiştir.

Neler Farklı Bir Aşırı Yükleme Sayılır

Bir aşırı yükleme yalnızca parametre listesiyle ayırt edilir. Şunları değiştirebilirsin:

int  area(int side);                 // 1 parametre
int  area(int width, int height);    // 2 parametre  -> farklı
double area(double r);               // farklı tip -> farklı

void log(string msg, int level);     // sıra önemlidir...
void log(int level, string msg);     // ...dolayısıyla bu da farklıdır

Bunların her biri geçerli ve ayrı bir aşırı yüklemedir. Derleyici, area adlı tüm fonksiyonlardan bir aday kümesi oluşturur, ardından argüman sayısı ve tipine göre eşleştirir.

Dönüş Tipi Tek Başına Yeterli Değil

İşte neredeyse herkesi tökezleten tuzak: dönüş tipine göre aşırı yükleme yapamazsın. Dönüş değeri, aşırı yüklemeyi seçmede hiçbir rol oynamaz, çünkü derleyici hangi fonksiyonu çağıracağına argümanlardan karar verir - dönen değere bakmadan çok önce.

int    convert(double x);   // OK
double convert(double x);   // HATA: yeniden tanımlama - yalnızca dönüş tipi farklı

Bu derlenmez. Parametre listeleri aynıysa, aşırı yükleme açısından iki bildirim aynı fonksiyondur ve bir yeniden tanımlama hatası alırsın. Sonuç tipine göre dallanmak için bir parametreyi değiştir (ya da çağrı noktasında şablonları kullan veya çağrı noktasında bir tür dönüşümü uygula).

Aşırı Yükleme Çözümlemesi Kazananı Nasıl Seçer

Bir çağrı yaptığında, derleyici uygun tüm aşırı yüklemeleri sıralar ve en iyi eşleşmeyi seçer. Kabaca, şu sırayla tercih eder:

  1. Bir tam eşleşme (dönüşüm gerekmez).
  2. Bir yükseltme (örn. char veya short -> int, float -> double).
  3. Bir standart dönüşüm (örn. int -> double, double -> int, temel sınıfa işaretçi).

Diğerlerinin hepsinden kesinlikle daha iyi olan tam olarak bir aşırı yükleme varsa, o kazanır. Bir tam eşleşmenin bir dönüşümü nasıl yendiğini izle:

'A' bir char'tır, ama int'e yükseltme double'a dönüşümden daha üstündür, bu yüzden int aşırı yüklemesini çağırır. Bu sıralama kuralları, aşırı yükleme çözümlemesinin genellikle "doğru olanı yapmasının" - ve ara sıra seni şaşırtmasının - nedenidir.

Belirsizlik Tuzağı

İki aşırı yükleme eşit derecede iyiyse - hiçbiri kesinlikle daha iyi değilse - derleyici tahmin etmeyi reddeder ve bir belirsiz çağrı bildirir. Ders kitabı örneği, her biri aynı dereceden bir dönüşüme ihtiyaç duyan iki aşırı yüklemedir:

void f(int x);
void f(double x);

f(0L);   // HATA: belirsiz - long -> int ve long -> double aynı dereceden dönüşümlerdir

Ne int ne de double, long için tam eşleşmedir ve her iki dönüşüm de aynı derecede yer alır, bu yüzden çağrı belirsizdir. İki temiz çözümün var:

İlgili bir sürpriz: bir dize değişmezi geçirmek. void g(const string&) ve void g(bool) ikisi de g("hi") için teklif verir ve bool kazanabilir, çünkü bir const char*, bir std::string inşa etmekten daha az adımda bool'a dönüşür (null değil -> true). Bir dize değişmezinin gizemli bir şekilde bool aşırı yüklemeni çağırdığını görürsen, sebebi budur - tam eşleşmeyi alması için bir const char* veya const string& aşırı yüklemesi ekle.

Aşırı Yükleme ve Varsayılan Argümanlar İyi Geçinmez

Varsayılan argümanlar aşırı yüklemenin yerini tutmaz ve ikisini birleştirmek belirsizlik yaratır. Her biri aynı çağrıyı yanıtlayabilir, bu yüzden derleyici seçim yapamaz:

void connect(string host, int port = 8080);   // 1 argümanla çağrılabilir
void connect(string host);                     // bu da 1 argümanla çağrılabilir

connect("localhost");   // HATA: belirsiz - ikisi de tek argümanla eşleşir

Her çağrı biçimi için tek bir yaklaşım seç. Davranış aynıysa ve sadece isteğe bağlı parametreler istiyorsan varsayılan argümanları kullan; farklı argüman listeleri gerçekten farklı kod çalıştırmalıysa aşırı yüklemeyi kullan. İkisini, iki imzanın aynı argüman sayısı için çakışacağı şekilde karıştırmak garantili bir belirsizlik hatasıdır.

Çivilenmesi gereken bir ayrım daha: aşırı yükleme, ezme (override) değildir. Aşırı yükleme, aynı kapsamdaki aynı isimli ama farklı parametreli fonksiyonlar arasında derleme zamanında çözülür. Ezme ise türetilmiş bir sınıftaki bir virtual fonksiyonu çalışma zamanında değiştirir ve aynı imzayı gerektirir - bu, ileride sanal fonksiyonlar için bir konu.

Sırada: Lambda'lar

Aşırı yükleme, bir isme derleme zamanında seçilen birden fazla tipli uygulama verir. Ancak bazen isimli bir fonksiyon hiç istemezsin - kullandığın yerde tanımlanan, çoğu zaman sort gibi bir algoritmaya geçirilecek küçük, tek seferlik bir fonksiyona ihtiyacın olur. İşte tam olarak lambda'lar budur: satır içinde yazabildiğin, çevredeki değişkenleri yakalayabildiğin ve tek bir ifadede devredebildiğin anonim fonksiyonlar. Sırada bunları nasıl yazacağımızı ve ne zaman tam isimli bir fonksiyonu geçtiklerini göreceğiz.

Sıkça Sorulan Sorular

C++'ta fonksiyon aşırı yükleme nedir?

Fonksiyon aşırı yükleme, parametre listeleri farklı olduğu (sayı, tip veya sıra bakımından) sürece aynı isimli birden fazla fonksiyon tanımlamana izin verir. Derleyici, verdiğin argümanlara bakarak hangisini çağıracağını seçer; bu yüzden print(42) ve print("hi") iki farklı print fonksiyonunu çağırabilir.

İki C++ fonksiyonu yalnızca dönüş tipiyle birbirinden ayrılabilir mi?

Hayır. Aşırı yüklemeler parametre listelerinde farklılaşmalıdır. int f(int) ve double f(int) bir derleme hatasıdır - dönüş tipi, aşırı yükleme çözümlemesinde kullanılan imzanın bir parçası değildir, çünkü derleyici aşırı yüklemeyi çağrı noktasındaki argümanlardan seçer; dönüş değeri henüz hiç kullanılmamışken.

Aşırı yüklenmiş fonksiyonlarda "belirsiz çağrı" hatasına ne yol açar?

İki aşırı yükleme eşit derecede iyi eşleştiğinde ve derleyici birini tercih edemediğinde olur. Klasik bir örnek, f(int) ve f(double)'ın f(0L) (bir long) ile çağrılmasıdır; burada ikisi de aynı dereceden bir dönüşüm gerektirir. Tam eşleşen bir aşırı yükleme ekleyerek veya argümanı istediğin tipe dönüştürerek düzeltebilirsin.

Coddy programming languages illustration

Coddy ile kodlamayı öğren

BAŞLA