Di C #, C ++ dan Java, saat Anda membuat parameter konstruktor, parameter tanpa parameter default hilang. Saya selalu menerima kenyataan ini, tetapi sekarang saya mulai bertanya-tanya mengapa.
Apa alasan perilaku ini? Apakah ini hanya "ukuran / dugaan keselamatan" yang mengatakan "Jika Anda telah membuat konstruktor sendiri, Anda mungkin tidak ingin yang implisit ini berkeliaran"? Atau apakah ia memiliki alasan teknis yang membuat mustahil bagi kompiler untuk menambahkan satu setelah Anda membuat konstruktor sendiri?
c#
java
c++
default-constructor
olagjo
sumber
sumber
Foo() = default;
untuk mendapatkan kembali default.Jawaban:
Tidak ada alasan bahwa kompiler tidak dapat menambahkan konstruktor jika Anda telah menambahkan konstruktor Anda sendiri - kompiler dapat melakukan hampir semua yang diinginkan! Namun, Anda harus melihat apa yang paling masuk akal:
Jadi, dalam setiap kasus, Anda dapat melihat bahwa perilaku kompiler saat ini paling masuk akal dalam hal menjaga maksud kode.
sumber
Ada tentu saja tidak ada alasan teknis mengapa bahasa memiliki harus dirancang dengan cara ini.
Ada empat opsi yang agak realistis yang bisa saya lihat:
Opsi 1 agak menarik, karena semakin saya kode semakin jarang saya benar - benar menginginkan konstruktor tanpa parameter. Suatu hari saya harus menghitung seberapa sering saya benar-benar menggunakan konstruktor default ...
Opsi 2 Saya setuju.
Opsi 3 bertentangan dengan aliran Java dan C #, untuk sisa bahasa. Tidak pernah ada yang Anda "hapus" secara eksplisit, kecuali jika Anda secara eksplisit membuat hal-hal yang lebih pribadi daripada yang secara default di Jawa.
Opsi 4 mengerikan - Anda benar - benar ingin dapat memaksa konstruksi dengan parameter tertentu. Apa
new FileStream()
artinya?Jadi pada dasarnya, jika Anda menerima premis bahwa menyediakan konstruktor default masuk akal sama sekali, saya percaya itu masuk akal untuk menekannya segera setelah Anda memberikan konstruktor sendiri.
sumber
struct
s, baik atau buruk.Edit. Sebenarnya, sementara apa yang saya katakan dalam jawaban pertama saya valid, ini adalah alasan sebenarnya .:
Pada awalnya ada C. C tidak berorientasi objek (Anda dapat mengambil pendekatan OO, tetapi tidak membantu Anda atau menegakkan apa pun).
Lalu ada C With Classes, yang kemudian dinamai C ++. C ++ berorientasi objek, dan karena itu mendorong enkapsulasi, dan memastikan invarian objek - setelah konstruksi dan pada awal dan akhir metode apa pun, objek berada dalam keadaan valid.
Hal alami yang harus dilakukan dengan ini, adalah untuk menegakkan bahwa kelas harus selalu memiliki konstruktor untuk memastikannya dimulai dalam keadaan yang valid - jika konstruktor tidak harus melakukan apa pun untuk memastikan ini, maka konstruktor kosong akan mendokumentasikan fakta ini .
Tetapi tujuan dengan C ++ adalah agar kompatibel dengan C sampai pada titik bahwa sebanyak mungkin, semua program C yang valid juga merupakan program C ++ yang valid (tidak lagi sebagai tujuan aktif, dan evolusi C terpisah ke C ++ berarti ia tidak lagi berlaku ).
Salah satu efek dari ini adalah duplikasi fungsi antara
struct
danclass
. Yang pertama melakukan hal-hal dengan cara C (semuanya publik secara default) dan yang terakhir melakukan hal-hal dengan cara OO yang baik (semuanya pribadi secara default, pengembang secara aktif membuat publik apa yang mereka inginkan publik).Lain adalah bahwa agar C
struct
, yang tidak bisa memiliki konstruktor karena C tidak memiliki konstruktor, untuk valid dalam C ++, maka harus ada makna untuk ini kepada cara C ++ memandangnya. Jadi, sementara tidak memiliki konstruktor akan bertentangan dengan praktik OO untuk secara aktif memastikan invarian, C ++ menganggap ini berarti bahwa ada konstruktor tanpa parameter default yang bertindak seperti memiliki tubuh kosong.Semua C
structs
sekarang valid C ++structs
, (yang berarti mereka sama dengan C ++classes
dengan semuanya - anggota dan warisan - publik) diperlakukan dari luar seolah-olah ia memiliki konstruktor tunggal tanpa parameter.Namun jika Anda memasukkan konstruktor ke dalam
class
ataustruct
, maka Anda melakukan hal-hal dengan cara C ++ / OO daripada cara C, dan tidak ada kebutuhan untuk konstruktor default.Karena berfungsi sebagai singkatan, orang-orang terus menggunakannya bahkan ketika kompatibilitas tidak mungkin terjadi (menggunakan fitur C ++ lainnya yang tidak ada di C).
Oleh karena itu ketika Java muncul (berdasarkan C ++ dalam banyak hal) dan kemudian C # (berdasarkan C ++ dan Java dengan cara yang berbeda), mereka mempertahankan pendekatan ini karena sesuatu yang mungkin sudah digunakan oleh pembuat kode.
Stroustrup menulis tentang ini dalam Bahasa Pemrograman C ++ dan lebih dari itu, dengan lebih fokus pada "mengapa" bahasa dalam Desain dan Evolusi C ++ .
=== Jawaban Asli ===
Katakanlah ini tidak terjadi.
Katakanlah saya tidak ingin konstruktor tanpa parameter, karena saya tidak dapat membuat kelas saya menjadi keadaan yang bermakna tanpa satu. Memang, ini adalah sesuatu yang dapat terjadi dengan
struct
di C # (tetapi jika Anda tidak dapat menggunakan semua-nol-dan-nulls yang berartistruct
di C # Anda paling baik menggunakan optimasi yang tidak terlihat oleh publik, dan jika tidak memiliki desain cacat dalam menggunakanstruct
).Untuk membuat kelas saya dapat melindungi invariannya, saya perlu
removeDefaultConstructor
kata kunci khusus . Paling tidak, saya harus membuat konstruktor tanpa parameter pribadi untuk memastikan tidak ada kode panggilan yang memanggil default.Yang menyulitkan bahasa lagi. Lebih baik tidak melakukannya.
Secara keseluruhan, lebih baik tidak menganggap menambahkan konstruktor sebagai menghapus default, lebih baik untuk berpikir tidak memiliki konstruktor sama sekali sebagai gula sintaksis untuk menambahkan konstruktor tanpa parameter yang tidak melakukan apa-apa.
sumber
Konstruktor tanpa parameter default ditambahkan jika Anda tidak melakukan apa pun untuk mengendalikan pembuatan objek. Setelah Anda membuat konstruktor tunggal untuk mengambil kendali, kompiler "mundur" dan membiarkan Anda memiliki kontrol penuh.
Jika tidak seperti ini, Anda perlu cara eksplisit menonaktifkan konstruktor default jika Anda hanya ingin objek dapat dibangun melalui konstruktor dengan parameter.
sumber
Ini adalah fungsi kenyamanan dari kompiler. Jika Anda mendefinisikan Konstruktor dengan parameter tetapi tidak mendefinisikan konstruktor tanpa parameter, kemungkinan Anda tidak ingin mengizinkan konstruktor tanpa parameter jauh lebih tinggi.
Ini adalah kasus untuk banyak objek yang tidak masuk akal untuk menginisialisasi dengan konstruktor kosong.
Jika tidak, Anda harus mendeklarasikan konstruktor tanpa parameter pribadi untuk setiap kelas yang ingin Anda batasi.
Menurut pendapat saya itu bukan gaya yang baik untuk memungkinkan konstruktor tanpa parameter untuk kelas yang membutuhkan parameter berfungsi.
sumber
Saya pikir pertanyaannya harus sebaliknya: Mengapa Anda tidak perlu mendeklarasikan konstruktor default jika Anda belum mendefinisikan konstruktor lain?
Konstruktor wajib untuk kelas non-statis.
Jadi saya pikir jika Anda belum mendefinisikan konstruktor, konstruktor default yang dihasilkan hanya fitur yang nyaman dari kompiler C #, juga kelas Anda tidak akan valid tanpa konstruktor. Jadi tidak ada yang salah dengan menghasilkan konstruktor yang tidak melakukan apa-apa. Jelas terlihat lebih bersih daripada memiliki konstruktor kosong di sekitar.
Jika Anda telah mendefinisikan konstruktor, kelas Anda valid, jadi mengapa kompilator harus menganggap Anda menginginkan konstruktor default? Bagaimana jika Anda tidak menginginkannya? Menerapkan atribut untuk memberi tahu kompiler untuk tidak menghasilkan konstruktor default itu? Saya pikir itu bukan ide yang bagus.
sumber
Konstruktor default dapat dibangun hanya ketika kelas tidak memiliki konstruktor. Kompiler ditulis sedemikian rupa untuk menyediakan ini hanya sebagai mekanisme cadangan.
Jika Anda memiliki konstruktor berparameter, Anda mungkin tidak ingin objek dibuat menggunakan konstruktor default. Seandainya kompiler menyediakan konstruktor default, Anda harus menulis konstruktor no-arg dan menjadikannya pribadi untuk mencegah objek dibuat tanpa menggunakan argumen.
Juga, akan ada peluang lebih tinggi Anda lupa menonaktifkan, atau 'memprivatisasi' konstruktor default, dan dengan demikian menyebabkan kesalahan fungsional potensial yang sulit ditangkap.
Dan sekarang Anda harus secara eksplisit mendefinisikan konstruktor no-arg jika Anda ingin objek dibuat dengan cara default atau dengan melewatkan parameter. Ini sangat diperiksa, dan kompiler mengeluh sebaliknya, dengan demikian memastikan tidak ada celah di sini.
sumber
Premis
Perilaku ini dapat dilihat sebagai perpanjangan alami dari keputusan untuk kelas untuk memiliki konstruktor tanpa parameter publik default . Berdasarkan pertanyaan yang diajukan, kami mengambil keputusan ini sebagai premis dan menganggap bahwa kami tidak mempertanyakannya dalam hal ini.
Cara untuk Menghapus Konstruktor Default
Oleh karena itu harus ada cara untuk menghapus konstruktor tanpa parameter publik default. Penghapusan ini dapat dilakukan dengan cara-cara berikut:
Memilih Solusi Terbaik
Sekarang kita bertanya pada diri sendiri: Jika tidak ada konstruktor tanpa parameter, apa yang harus diganti? dan Di bawah jenis skenario apa kita ingin menghapus konstruktor tanpa parameter publik default?
Segalanya mulai jatuh pada tempatnya. Pertama, harus diganti dengan konstruktor dengan parameter, atau dengan konstruktor non-publik. Kedua, skenario di mana Anda tidak ingin konstruktor tanpa parameter adalah:
Kesimpulan
Di sana kita memilikinya - persis dua cara yang C #, C ++ dan Java memungkinkan penghapusan konstruktor tanpa parameter publik default.
sumber
= delete
untuk tujuan ini.Saya pikir ini ditangani oleh kompiler. Jika Anda membuka
.net
perakitan diILDASM
Anda akan melihat konstruktor default, bahkan jika itu tidak ada dalam kode. Jika Anda mendefinisikan konstruktor berparameter, konstruktor default tidak akan terlihat.Sebenarnya ketika Anda mendefinisikan kelas (non-statis), kompiler menyediakan fitur ini dengan berpikir bahwa Anda hanya akan membuat instance. Dan jika Anda ingin operasi tertentu dilakukan, Anda pasti akan memiliki konstruktor sendiri.
sumber
Karena ketika Anda tidak mendefinisikan konstruktor, kompiler secara otomatis menghasilkan konstruktor untuk Anda yang tidak mengambil argumen apa pun. Ketika Anda menginginkan sesuatu yang lebih dari konstruktor, Anda menumpanginya. Ini BUKAN fungsi overloading. Jadi satu-satunya konstruktor yang dilihat kompiler adalah konstruktor Anda yang mengambil argumen. Untuk mengatasi masalah ini, Anda dapat memberikan nilai default jika konstruktor dilewatkan tanpa nilai.
sumber
Kelas membutuhkan konstruktor. Ini adalah persyaratan wajib.
Saya akan menjawab pertanyaan Anda dengan yang lain, mengapa kami ingin selalu menjadi konstruktor tanpa parameter default? ada kasus di mana ini tidak diinginkan, sehingga pengembang memiliki kontrol untuk menambah atau menghapusnya sesuai kebutuhan.
sumber