Fonksiyon parametresinin varsayılan değeri


130

1.

int Add (int a, int b = 3);
int Add (int a, int b)
{

}

2.

int Add (int a, int b);
int Add (int a, int b = 3)
{

}

Her ikisi de çalışır; standart yol hangisidir ve neden ?

Yanıtlar:


203

Bildirimi bir başlık dosyasına, tanımı ayrı bir .cppdosyaya ve #includebaşlığı farklı bir .cppdosyaya koyarsanız, farkı görebilirsiniz.

Özellikle varsayalım:

lib.h

int Add(int a, int b);

lib.cpp

int Add(int a, int b = 3) {
   ...
}

test.cpp

#include "lib.h"

int main() {
    Add(4);
}

Derlemesi test.cppvarsayılan parametre bildirimini görmeyecek ve bir hata vererek başarısız olacaktır.

Bu nedenle, varsayılan parametre tanımı genellikle işlev bildiriminde belirtilir :

lib.h

int Add(int a, int b = 3);

Sonra bbirden çok kez tanımlanacak, her derleme birimi için bir kez, lib.hbu doğru mu?
httpinterpret

@httpinterpret: bir anlamda evet, varsayılan değeri başlığı içeren her dosya biçin bir kez tanımlanır . Ama sorun değil, çünkü işlevin yalnızca bir bildirimi var . .cppAdd
Greg Hewgill,

1
@httpinterpret Derleyici, arayan kodu oluşturulduğunda belirtilmemiş parametreyi varsayılan parametre ile ekleyecektir. Bu nedenle varsayılan değer, işlev uygulamasında değil işlev prototipinde olmalıdır ZORUNLU. Prototip değişkenleri tanımlamadığından parametre değişken tanımı anlamında tanımlanmamıştır .
harper

1
Hızlı bir çözümleme (sadece koda bakıp "Bu nedenle" ye kadar gitmemek) demek istediğinin tam tersini anlamamı sağladığından bu yanıt değiştirilebilirdi.
Gabriel Devillers

44

C ++ 'da, parametre listesindeki konumlarına göre varsayılan bağımsız değişkenlere uygulanan gereksinimler aşağıdaki gibidir:

  1. Belirli bir parametre için varsayılan bağımsız değişken bir defadan fazla belirtilmemelidir. Bir kereden fazla belirtmek (aynı varsayılan değerle bile) yasa dışıdır.

  2. Varsayılan bağımsız değişkenlere sahip parametreler, parametre listesinin sonunda bitişik bir grup oluşturmalıdır.

Şimdi, bunu göz önünde bulundurarak, C ++ 'da, yukarıdaki gereksinimler sürekli olarak karşılandığı sürece, işlevin bir bildiriminden diğerine varsayılan argümanlar içeren parametreler kümesini "büyütmenize" izin verilir.

Örneğin, varsayılan bağımsız değişkenler içermeyen bir işlev bildirebilirsiniz

void foo(int a, int b);

Böyle bir bildirimden sonra bu işlevi çağırmak için her iki argümanı da açıkça belirtmeniz gerekir.

Daha sonra (daha aşağı) aynı çeviri biriminde, tekrar beyan edebilirsiniz, ancak bu sefer bir varsayılan bağımsız değişkenle

void foo(int a, int b = 5);

ve bu noktadan sonra, onu sadece bir açık argümanla çağırabilirsiniz.

Daha aşağıda, bir varsayılan argüman daha ekleyerek yeniden ilan edebilirsiniz.

void foo(int a = 1, int b);

ve bu noktadan sonra onu hiçbir açık argüman olmadan çağırabilirsiniz.

Tam örnek aşağıdaki gibi görünebilir

void foo(int a, int b);

int main()
{
  foo(2, 3);

  void foo(int a, int b = 5); // redeclare
  foo(8); // OK, calls `foo(8, 5)`

  void foo(int a = 1, int b); // redeclare again
  foo(); // OK, calls `foo(1, 5)`
}

void foo(int a, int b)
{
  // ...
}

Sorunuzdaki koda gelince, her iki değişken de mükemmel şekilde geçerlidir, ancak farklı şeyler ifade ederler. İlk değişken, hemen ikinci parametre için varsayılan bir bağımsız değişken bildirir. İkinci değişken, başlangıçta işlevinizi varsayılan bağımsız değişkenler olmadan bildirir ve ardından ikinci parametre için bir tane ekler.

Her iki bildiriminizin net etkisi (yani ikinci bildirimi izleyen kod tarafından görülme şekli) tamamen aynıdır: işlevin ikinci parametresi için varsayılan bağımsız değişkeni vardır. Bununla birlikte, birinci ve ikinci bildirimler arasında bir miktar kod sıkıştırmayı başarırsanız, bu iki değişken farklı davranacaktır. İkinci varyantta, işlevin bildirimler arasında varsayılan bağımsız değişkenleri yoktur, bu nedenle her iki bağımsız değişkeni de açıkça belirtmeniz gerekir.


Kodunuzun void foo (int a = 1, int b) tanımlı çalışacağını sanmıyorum. Bir isteğe bağlı parametreden sonra tüm isteğe bağlı parametrelere sahip olmanız gerekir. Bu bir sözdizimi hatası (en azından sistemimde g ++ 4.5.3 ile).
Nilesh

@Nilesh: Ben açıkça (ve bu örneğin bütün mesele olan) için yukarıda belirttiğimiz gibi void foo(int a = 1, int b)bu ilan edilmelidir çalışmaya sonra void foo(int a, int b = 5) . Evet, işe yarayacak. Ve hayır, bu bir sözdizimi hatası değil. g ++ 4.5.3 onu mükemmel bir şekilde derleyecektir.
AnT

Tamam, yani işlev önceki bildirimden b değerini alıyor. Şimdi bir şey alıyorum. Teşekkürler :-)
Nilesh

1
@Nilesh: Evet, varsayılan bağımsız değişken bildirimleri, çeviri birimindeki önceki tüm bildirimlerde toplanır.
AnT

1
İşlev prototiplerimi değişken isimler olmadan yazmayı seviyorum, örneğin int foo(int). int foo(int=5)Parametre isimlerini dışarıda bırakarak tekrar yazabileceğimi görüyorum . Henüz kimse bundan bahsetmemiş gibi görünüyor.
Victor Eijkhout

5

Birinci yol ikinciye tercih edilir.

Bunun nedeni, başlık dosyasının parametrenin isteğe bağlı olduğunu ve varsayılan değerinin ne olacağını göstermesidir. Ek olarak, bu, karşılık gelen .cpp dosyasının uygulaması ne olursa olsun, varsayılan değerin aynı olmasını sağlayacaktır.

İkinci şekilde, ikinci parametre için varsayılan bir değerin garantisi yoktur. Varsayılan değer, karşılık gelen .cpp dosyasının nasıl uygulandığına bağlı olarak değişebilir.


4

Varsayılan bağımsız değişkenler, işlev adının ilk geçtiği yerle (tipik olarak işlev prototipinde) belirtilmelidir. İşlev tanımının aynı zamanda prototip görevi görmesi nedeniyle işlev prototipi atlanırsa, varsayılan bağımsız değişkenler işlev başlığında belirtilmelidir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.