Maksud saya, ini masalah memilih kata lebih dari ada perbedaan antara fungsi dan panggilan konstruktor. Benda yang dinamai "konstruktor suatu objek" juga dapat dinamai "fungsi dengan object
tipe pengembalian nama object
".
Orang dapat berargumen bahwa C ++ tidak memungkinkan seseorang untuk memiliki fungsi dan tipe nama yang sama; Namun, ada solusi untuk melakukannya. C ++ memiliki gula sintaksis khusus (yang dinamai konstruktor) yang dengannya Anda dapat membuat fungsi dengan object
tipe pengembalian nama object
. Jadi saya pikir konstruktor dapat dilihat dan digunakan sebagai fungsi berdiri bebas.
Apakah ada beberapa perbedaan semantik penting yang saya lewatkan di sini?
c++
functions
constructors
type
pengguna3123061
sumber
sumber
Jawaban:
Konstruktor pada dasarnya adalah metode, ya, tetapi itu adalah metode khusus.
Misalnya, dalam C ++ konstruktor bukan hanya fungsi yang mengembalikan contoh baru dari jenis itu. Jika ya, warisan tidak akan berhasil. Anda tidak dapat memanggil konstruktor dasar, karena mereka akan mengembalikan contoh baru juga. Anda akan berakhir dengan instance baru A, yang kemudian dikembalikan ke konstruktor B yang membuat instance baru B, yang kemudian dikembalikan ke konstruktor C, dll.
Alih-alih konstruktor lebih merupakan metode inisialisasi yang secara otomatis dipanggil oleh pengalokasi instance. Ketika Anda, katakanlah, panggil "baru" untuk membuat objek di heap, itu mengalokasikan memori untuk tipe yang Anda minta (menggunakan pengalokasi memori, seperti malloc), lalu memanggil metode konstruktor di atasnya. Kompilator memiliki aturan khusus untuk bagaimana, dan dalam urutan apa, konstruktor itu dapat memanggil konstruktor lain. Misalnya, dalam C #, jika Anda tidak secara eksplisit memanggil konstruktor basis, kompiler akan menambahkan panggilan ke konstruktor default dasar.
Ini adalah aturan-aturan tentang bagaimana kompiler menangani konstruktor yang membuatnya berbeda dari "fungsi bernama .ctor yang mengembalikan turunan dari tipe".
sumber
new
untuk membangun objek di C ++, karena memiliki variabel otomatis.Tidak, konstruktor
object
sangat berbeda dari fungsi yang dipanggilobject
dan kembaliobject
. Konstruktor tidak memiliki nama, tetapi sebagian besar teknis. Perbedaan yang lebih penting adalah bahwa konstruktor tidak memiliki tipe pengembalian dan tidak dapat dipanggil secara langsung.Konstruktor tidak mengembalikan apa-apa karena diberi blok memori dan beroperasi pada memori itu di tempat. Mungkin membantu jika Anda lupa nama "konstruktor" sejenak dan menganggapnya sebagai penginisialisasi . Tujuan konstruktor bukan untuk membangun objek "keluar dari udara tipis." Tujuannya adalah untuk menginisialisasi objek di tempat yang tepat di memori di mana ia perlu berada.
Jika sebuah konstruktor mengembalikan sebuah objek, objek yang dikembalikan (nilai pengembalian) harus tinggal di suatu tempat (mungkin di stack), dan di sana, ia perlu diinisialisasi entah bagaimana - kita sedang menjalankan perulangan di sini.
Ini sejalan dengan fakta bahwa seorang konstruktor tidak pernah dapat dipanggil secara langsung. Jika Anda memiliki kelas
object
dan menggunakan ekspresi diobject()
suatu tempat, itu tidak memiliki semantik "panggil konstruktorobject
." Memiliki semantik "buat objek tipe sementaraobject
." Compiler menerjemahkan ini ke dalam mengalokasikan beberapa tempat untuk sementara untuk tinggal (mungkin / umumnya di stack), dan memanggil konstruktor untuk membangun (= menginisialisasi) sebuah objek di tempat itu.Prinsip yang sama berlaku saat menggunakan
new object()
. Ini adalah ekspresi baru, yang melakukan dua hal:operator new
(yang mengembalikan avoid*
) untuk mengalokasikan memori mentah untuk objek.Memikirkan konstruktor
object
sebagai fungsi seperti ini:salah. Jika ada, cara konstruktor bekerja lebih dekat dengan ini:
Dengan pengecualian bahwa Anda tidak pernah dapat memanggilnya secara langsung. Itu selalu hanya dipanggil ketika ditentukan oleh konstruksi bahasa yang berbeda. Bahkan penempatan baru (juga dikenal sebagai trik "panggil konstruktor di sini"),,
new (&place_for_object) object()
tidak memanggil konstruktor secara langsung. Ini diterjemahkan menjadi panggilan ke bentuk penempatan-baruoperator new
yang mengembalikan argumennya, diikuti oleh panggilan ke konstruktor (sama seperti ekspresi-baru lainnya).sumber
Upaya Anda untuk menulis ulang salah.
Meskipun konstruktor terlihat seperti fungsi anggota dengan nama yang sama dengan nama kelas, faktanya adalah konstruktor tidak benar-benar memiliki nama sama sekali. Ini secara eksplisit dinyatakan dalam standar C ++ (bagian [class.ctor] / 1):
Sejauh: "Saya pikir konstruktor dapat dilihat dan digunakan sebagai fungsi berdiri bebas" berjalan ... well, saya tidak yakin apa yang Anda maksud. Fungsi bebas tentu saja tidak bisa menjadi konstruktor - konstruktor harus menjadi anggota kelas. Pada saat yang sama, Anda tentu dapat mendefinisikan fungsi bebas yang membuat objek dan mengembalikan instance objek itu. Fungsi bebas itu bahkan dapat (semacam) memiliki nama yang sama dengan jenis objek yang dibuatnya, jika Anda ingin cukup buruk. Misalnya, Anda bisa mendefinisikan kelas di dalam namespace, lalu mendefinisikan fungsi di luar namespace:
Hal ini tidak benar-benar nama yang sama (fungsi ini hanya
bar
dan kelas adalahfoo::bar
), tapi tergantung pada sudut pandang Anda, Anda bisa semacam melihat mereka seperti itu pula.Fungsi bebas semacam itu tidak akan memiliki karakteristik kunci lain dari konstruktor. Doa seorang konstruktor bisa sepenuhnya implisit. Sebagai contoh, jika saya memiliki kelas seperti:
... lalu kode seperti:
... dapat membuat objek foo sementara dari
1
sehingga dapat meneruskan objek foo itu kefoo::operator+
. Itu tidak akan terjadi dengan fungsi bebas, bahkan jika fungsi bebas itu didefinisikan untuk mengambil jenis parameter yang tepat dan mengembalikan jenis hasil yang diperlukan. Untuk konversi tersirat seperti itu, diperlukan konstruktor.sumber
Pertama, konstruktor tidak mengembalikan apa pun dan, sebagai konsekuensinya, tidak memiliki tipe pengembalian.
Kedua, konstruktor berbeda karena Anda tidak dapat benar-benar memanggil konstruktor secara langsung dengan cara Anda memanggil fungsi. Sebaliknya, jika Anda mendeklarasikan variabel, konstruktor yang sesuai dipanggil oleh runtime.
Ketiga, dalam hal pewarisan, fungsi reguler di subclass menimpa fungsi di kelas induk. Konstruktor, di sisi lain, cascade - induk kelas disebut pertama, kemudian subkelas konstruktor.
Keempat, konstruktor dapat memiliki daftar inisialisasi, sedangkan fungsi "normal" tidak bisa.
sumber