Nilai default dari parameter fungsi

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)
{

}

Keduanya bekerja; yang merupakan cara standar dan mengapa ?

httpinterpret
sumber

Jawaban:

203

Jika Anda meletakkan deklarasi dalam file header, dan definisi dalam .cppfile terpisah , dan #includeheader dari .cppfile yang berbeda , Anda akan dapat melihat perbedaannya.

Secara khusus, anggap:

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);
}

Kompilasi test.cpptidak akan melihat deklarasi parameter default, dan akan gagal dengan kesalahan.

Untuk alasan ini, definisi parameter default biasanya ditentukan dalam deklarasi fungsi :

lib.h

int Add(int a, int b = 3);
Greg Hewgill
sumber
Kemudian bakan didefinisikan beberapa kali, satu kali untuk setiap unit kompilasi yang termasuk lib.h, apakah itu benar?
httpinterpretasikan
@ httpsinterpretasikan: di satu sisi ya, nilai default bdidefinisikan satu kali untuk setiap .cpp file yang menyertakan header. Tapi tidak apa-apa, karena Anda hanya punya satu deklarasi Addfungsi.
Greg Hewgill
1
@ httpinterpretasi Kompiler akan menambahkan parameter yang tidak ditentukan oleh parameter default ketika kode pemanggil dibuat. Itu sebabnya nilai default HARUS dalam prototipe fungsi dan bukan dalam implementasi fungsi. Parameter tidak didefinisikan dalam arti definisi variabel karena prototipe tidak mendefinisikan variabel.
pemain harpa
1
Jawaban ini dapat diedit karena penguraian cepat (hanya melihat kode dan tidak pergi sampai "Karena alasan ini,") membuat saya memahami kebalikan dari apa yang Anda maksudkan.
Gabriel Devillers
44

Dalam C ++ persyaratan yang dikenakan pada argumen default sehubungan dengan lokasi mereka dalam daftar parameter adalah sebagai berikut:

  1. Argumen default untuk parameter yang diberikan harus ditentukan tidak lebih dari sekali. Menentukannya lebih dari sekali (bahkan dengan nilai default yang sama) adalah ilegal.

  2. Parameter dengan argumen default harus membentuk grup yang berdekatan di akhir daftar parameter.

Sekarang, dengan mengingat hal itu, dalam C ++ Anda diizinkan untuk "menumbuhkan" set parameter yang memiliki argumen default dari satu deklarasi fungsi ke yang berikutnya, selama persyaratan di atas terus terpenuhi.

Misalnya, Anda dapat mendeklarasikan fungsi tanpa argumen default

void foo(int a, int b);

Untuk memanggil fungsi itu setelah deklarasi seperti itu, Anda harus menentukan kedua argumen secara eksplisit.

Kemudian (lebih jauh ke bawah) di unit terjemahan yang sama, Anda dapat mendeklarasikannya kembali, tetapi kali ini dengan satu argumen default

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

dan mulai saat ini Anda dapat menyebutnya hanya dengan satu argumen eksplisit.

Lebih jauh ke bawah Anda dapat mendeklarasikannya lagi menambahkan satu argumen default lagi

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

dan mulai saat ini Anda dapat menyebutnya tanpa argumen eksplisit.

Contoh lengkapnya mungkin terlihat sebagai berikut

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)
{
  // ...
}

Adapun kode dalam pertanyaan Anda, kedua varian benar-benar valid, tetapi keduanya memiliki arti berbeda. Varian pertama mendeklarasikan argumen default untuk parameter kedua segera. Varian kedua awalnya menyatakan fungsi Anda tanpa argumen default dan kemudian menambahkan satu untuk parameter kedua.

Efek bersih dari kedua deklarasi Anda (yaitu cara dilihat oleh kode yang mengikuti deklarasi kedua) persis sama: fungsi memiliki argumen default untuk parameter kedua. Namun, jika Anda berhasil memeras beberapa kode antara deklarasi pertama dan kedua, kedua varian ini akan berperilaku berbeda. Pada varian kedua fungsi tidak memiliki argumen default antara deklarasi, jadi Anda harus menentukan kedua argumen secara eksplisit.

Semut
sumber
Saya tidak berpikir kode Anda didefinisikan void foo (int a = 1, int b) akan berfungsi. Anda harus memiliki semua parameter opsional setelah satu parameter opsional. Ini kesalahan sintaks (setidaknya dengan g ++ 4.5.3 di sistem saya).
Nilesh
@ Nilesh: Seperti yang saya katakan secara eksplisit di atas (dan yang merupakan inti dari contoh ini) untuk void foo(int a = 1, int b)bekerja harus dinyatakan setelah void foo(int a, int b = 5) . Ya, itu akan berhasil. Dan tidak, ini bukan kesalahan sintaksis. g ++ 4.5.3 akan mengkompilasinya dengan sangat baik.
AnT
Oke jadi fungsinya mengambil nilai b dari deklarasi sebelumnya. Dapatkan barang itu sekarang. Terima kasih :-)
Nilesh
1
@Nilesh: Ya, deklarasi argumen default diakumulasikan di semua deklarasi sebelumnya di unit terjemahan.
AnT
1
Saya suka menulis prototipe fungsi saya tanpa nama variabel int foo(int). Saya menemukan bahwa saya dapat menulis int foo(int=5)lagi, meninggalkan nama parameter. Sepertinya belum ada yang menyebutkan hal itu.
Victor Eijkhout
5

Cara pertama lebih disukai daripada yang kedua.

Ini karena file header akan menunjukkan bahwa parameternya opsional dan berapa nilai defaultnya. Selain itu, ini akan memastikan bahwa nilai default akan sama, tidak peduli penerapan file .cpp yang sesuai.

Dengan cara kedua, tidak ada jaminan nilai default untuk parameter kedua. Nilai default dapat berubah, tergantung pada bagaimana file .cpp yang sesuai diimplementasikan.

pengguna342264
sumber
4

Argumen default harus ditentukan dengan kemunculan pertama nama fungsi — biasanya, dalam prototipe fungsi. Jika prototipe fungsi dihilangkan karena definisi fungsi juga berfungsi sebagai prototipe, maka argumen default harus ditentukan dalam header fungsi.

clyfe
sumber