Saya sebagian menggunakan daftar inisialisasi anggota dengan konstruktor saya ... tapi saya sudah lama lupa alasan di balik ini ...
Apakah Anda menggunakan daftar inisialisasi anggota di konstruktor Anda? Jika demikian, mengapa? Jika tidak, mengapa tidak?
c++
oop
object-construction
paxos1977
sumber
sumber
Jawaban:
Untuk anggota kelas POD , tidak ada bedanya, itu hanya masalah gaya. Untuk anggota kelas yang merupakan kelas, maka itu menghindari panggilan yang tidak perlu ke konstruktor default. Mempertimbangkan:
Dalam hal ini, konstruktor untuk
B
akan memanggil konstruktor default untukA
, dan kemudian menginisialisasia.x
ke 3. Cara yang lebih baik bagiB
konstruktor untuk langsung memanggilA
konstruktor dalam daftar penginisialisasi:Hal ini hanya akan memanggil
A
'sA(int)
konstruktor dan tidak konstruktor default. Dalam contoh ini, perbedaannya dapat diabaikan, tetapi bayangkan jika Anda yangA
membangun default akan melakukan lebih, seperti mengalokasikan memori atau membuka file. Anda tidak ingin melakukan itu dengan tidak perlu.Selain itu, jika kelas tidak memiliki konstruktor default, atau Anda memiliki
const
variabel anggota, Anda harus menggunakan daftar penginisialisasi:sumber
Terlepas dari alasan kinerja yang disebutkan di atas, jika kelas Anda menyimpan referensi ke objek yang diteruskan sebagai parameter konstruktor atau kelas Anda memiliki variabel const, maka Anda tidak punya pilihan selain menggunakan daftar penginisialisasi.
sumber
Salah satu alasan penting untuk menggunakan daftar penginisialisasi konstruktor yang tidak disebutkan dalam jawaban di sini adalah inisialisasi kelas dasar.
Sesuai urutan konstruksi, kelas dasar harus dibangun sebelum kelas anak. Tanpa daftar penginisialisasi konstruktor, ini dimungkinkan jika kelas dasar Anda memiliki konstruktor default yang akan dipanggil sebelum memasuki konstruktor kelas anak.
Tetapi, jika kelas dasar Anda hanya memiliki konstruktor parameter, maka Anda harus menggunakan daftar penginisialisasi konstruktor untuk memastikan bahwa kelas dasar Anda diinisialisasi sebelum kelas anak.
Inisialisasi Subobjects yang hanya memiliki konstruktor berparameter
Efisiensi
Menggunakan daftar penginisialisasi konstruktor, Anda menginisialisasi anggota data Anda untuk menyatakan secara tepat yang Anda butuhkan dalam kode Anda daripada menginisialisasi mereka ke keadaan default mereka & kemudian mengubah negara mereka ke yang Anda butuhkan dalam kode Anda.
Jika anggota data const non-statis di kelas Anda memiliki konstruktor default & Anda tidak menggunakan daftar penginisialisasi konstruktor, Anda tidak akan dapat menginisialisasi mereka ke keadaan yang dimaksudkan karena mereka akan diinisialisasi ke keadaan default mereka.
Anggota data referensi harus diinisialisasi ketika kompiler memasuki konstruktor karena referensi tidak dapat dideklarasikan & diinisialisasi nanti. Ini hanya mungkin dengan daftar penginisialisasi konstruktor.
sumber
Di samping masalah kinerja, ada satu lagi yang sangat penting yang saya sebut rawatan dan perluasan kode.
Jika T adalah POD dan Anda mulai memilih daftar inisialisasi, maka jika suatu kali T akan berubah menjadi tipe non-POD, Anda tidak perlu mengubah apa pun di sekitar inisialisasi untuk menghindari panggilan konstruktor yang tidak perlu karena sudah dioptimalkan.
Jika tipe T memang memiliki konstruktor default dan satu atau lebih konstruktor yang ditentukan pengguna dan satu kali Anda memutuskan untuk menghapus atau menyembunyikan yang default, maka jika daftar inisialisasi digunakan, Anda tidak perlu memperbarui kode jika konstruktor yang ditentukan pengguna karena mereka sudah diimplementasikan dengan benar.
Sama dengan anggota const atau anggota referensi, katakanlah awalnya T didefinisikan sebagai berikut:
Selanjutnya, Anda memutuskan untuk memenuhi syarat sebagai const, jika Anda akan menggunakan daftar inisialisasi dari awal, maka ini adalah perubahan baris tunggal, tetapi memiliki T didefinisikan seperti di atas, itu juga perlu menggali definisi konstruktor untuk menghapus tugas:
Bukan rahasia bahwa pemeliharaan jauh lebih mudah dan lebih rentan kesalahan jika kode ditulis bukan oleh "kode monyet" tetapi oleh seorang insinyur yang membuat keputusan berdasarkan pertimbangan yang lebih dalam tentang apa yang dia lakukan.
sumber
Sebelum badan konstruktor dijalankan, semua konstruktor untuk kelas induknya dan kemudian untuk bidangnya dipanggil. Secara default, konstruktor tanpa argumen dipanggil. Daftar inisialisasi memungkinkan Anda memilih konstruktor mana yang dipanggil dan argumen apa yang diterima konstruktor.
Jika Anda memiliki referensi atau bidang const, atau jika salah satu kelas yang digunakan tidak memiliki konstruktor default, Anda harus menggunakan daftar inisialisasi.
sumber
Di sini kompiler mengikuti langkah-langkah berikut untuk membuat objek bertipe MyClass
1. Konstruktor tipe disebut pertama untuk "a".
2. Operator penugasan "Type" disebut bagian dalam konstruktor MyClass () untuk ditugaskan
Dan akhirnya destruktor "Type" dipanggil untuk "a" karena keluar dari ruang lingkup.
Sekarang pertimbangkan kode yang sama dengan konstruktor MyClass () dengan Initializer List
Dengan Daftar Initializer, langkah-langkah berikut diikuti oleh kompiler:
sumber
Hanya dengan menambahkan beberapa info tambahan untuk menunjukkan seberapa besar perbedaan yang dapat dibuat oleh daftar inisialisasi anggota . Dalam leetcode 303 Range Sum Query - Immutable, https://leetcode.com/problems/range-sum-query-immutable/ , di mana Anda perlu membuat dan menginisialisasi nol vektor dengan ukuran tertentu. Berikut adalah dua implementasi dan perbandingan kecepatan yang berbeda.
Tanpa daftar inisialisasi anggota , untuk mendapatkan AC harganya sekitar 212 ms .
Sekarang menggunakan daftar inisialisasi anggota , waktu untuk mendapatkan AC adalah sekitar 108 ms . Dengan contoh sederhana ini, sangat jelas bahwa, daftar inisialisasi anggota jauh lebih efisien . Semua pengukuran berasal dari waktu berjalan dari LC.
sumber
Sintaksis:
Perlu daftar Inisialisasi:
dalam program di atas, Ketika konstruktor kelas dieksekusi, Sam_x dan Sam_y dibuat. Kemudian dalam tubuh konstruktor, variabel data anggota tersebut didefinisikan.
Gunakan kasing:
Dalam C, variabel harus didefinisikan selama pembuatan. dengan cara yang sama di C ++, kita harus menginisialisasi variabel Const dan Reference selama pembuatan objek dengan menggunakan daftar Inisialisasi. jika kita melakukan inisialisasi setelah pembuatan objek (Inside constructor body), kita akan mendapatkan kesalahan waktu kompilasi.
Objek anggota kelas Sample1 (base) yang tidak memiliki konstruktor default
Saat membuat objek untuk kelas turunan yang secara internal akan memanggil konstruktor kelas turunan dan memanggil konstruktor kelas dasar (default). jika kelas dasar tidak memiliki konstruktor default, pengguna akan mendapatkan kesalahan waktu kompilasi. Untuk menghindari, kita harus memiliki keduanya
Nama parameter konstruktor kelas dan anggota data Kelas sama:
Seperti kita ketahui bersama, variabel lokal memiliki prioritas tertinggi daripada variabel global jika kedua variabel tersebut memiliki nama yang sama. Dalam hal ini, program mempertimbangkan nilai "i" {variabel kiri dan kanan. yaitu: i = i} sebagai variabel lokal di konstruktor Sample3 () dan variabel anggota Kelas (i) ditimpa. Untuk menghindari, kita harus menggunakan keduanya
sumber
Seperti dijelaskan dalam Pedoman Inti C ++ C.49: Memilih inisialisasi untuk penugasan dalam konstruktor , mencegah panggilan yang tidak perlu ke konstruktor default.
sumber