Apakah ada alasan khusus bahwa ini akan memecah bahasa secara konseptual atau alasan tertentu bahwa ini secara teknis tidak mungkin dilakukan dalam beberapa kasus?
Penggunaannya akan dengan operator baru.
Sunting: Saya akan berhenti berharap mendapatkan "operator baru" dan "operator baru" saya secara langsung.
Inti pertanyaannya adalah: mengapa konstruktor istimewa ? Ingatlah selalu bahwa spesifikasi bahasa memberi tahu kita apa yang legal, tetapi belum tentu moral. Apa yang legal biasanya diinformasikan oleh apa yang secara logis konsisten dengan bagian bahasa yang lain, apa yang sederhana dan ringkas, dan apa yang layak untuk diimplementasikan oleh kompiler. Alasan yang mungkin dari komite standar dalam menimbang faktor-faktor ini adalah disengaja dan menarik - karena itu pertanyaannya.
std::make_unique
danstd::make_shared
dapat secara memadai memecahkan motivasi praktis yang mendasari untuk pertanyaan ini. Ini adalah metode templat, yang berarti seseorang perlu menangkap argumen input ke konstruktor, dan kemudian meneruskannya ke konstruktor yang sebenarnya.Jawaban:
Fungsi pointer-ke-anggota hanya masuk akal jika Anda memiliki lebih dari satu fungsi anggota dengan tanda tangan yang sama - jika tidak, hanya akan ada satu nilai yang mungkin untuk pointer Anda. Tetapi itu tidak mungkin untuk konstruktor, karena dalam C ++ konstruktor yang berbeda dari kelas yang sama harus memiliki tanda tangan yang berbeda.
Alternatif untuk Stroustrup adalah memilih sintaks untuk C ++ di mana konstruktor dapat memiliki nama yang berbeda dari nama kelas - tetapi itu akan mencegah beberapa aspek yang sangat elegan dari sintaks ctor yang ada dan membuat bahasa lebih rumit. Bagi saya yang terlihat seperti harga tinggi hanya untuk memungkinkan fitur yang jarang diperlukan yang dapat dengan mudah disimulasikan dengan "outsourcing" inisialisasi objek dari ctor ke
init
fungsi yang berbeda (fungsi anggota normal yang dapat menjadi pointer-ke-anggota dapat dibuat).sumber
memcpy(buffer, (&std::string)(int, char), size)
? (Mungkin sangat tidak halal, tapi ini C ++.)memcpy(buffer, strlen, size)
. Agaknya itu akan menyalin majelis, tetapi siapa yang tahu. Apakah kode itu dapat dipanggil atau tidak tanpa crash akan membutuhkan pengetahuan tentang kompiler yang Anda gunakan. Hal yang sama berlaku untuk menentukan ukuran. Ini akan sangat bergantung pada platform, tetapi banyak konstruksi C ++ non-portabel digunakan dalam kode produksi. Saya tidak melihat alasan untuk melarangnya.Konstruktor adalah fungsi yang Anda panggil saat objek belum ada, jadi itu tidak bisa menjadi fungsi anggota. Itu bisa statis.
Konstruktor sebenarnya dipanggil dengan pointer ini, setelah memori telah dialokasikan tetapi sebelum sepenuhnya diinisialisasi. Akibatnya seorang konstruktor memiliki sejumlah fitur istimewa.
Jika Anda memiliki pointer ke constructor itu harus menjadi pointer statis, sesuatu seperti fungsi pabrik, atau pointer khusus ke sesuatu yang akan dipanggil segera setelah alokasi memori. Itu tidak bisa menjadi fungsi anggota biasa dan masih berfungsi sebagai konstruktor.
Satu-satunya tujuan berguna yang terlintas dalam pikiran adalah jenis pointer khusus yang dapat diteruskan ke operator baru untuk memungkinkannya untuk tidak langsung pada konstruktor mana yang digunakan. Saya kira itu bisa berguna, tetapi akan memerlukan sintaks baru yang signifikan dan mungkin jawabannya adalah: mereka memikirkannya dan itu tidak sepadan dengan usaha.
Jika Anda hanya ingin refactor kode inisialisasi umum maka fungsi memori biasa biasanya merupakan jawaban yang cukup, dan Anda bisa mendapatkan pointer ke salah satu dari itu.
sumber
&A::A
tidak berfungsi di salah satu kompiler yang saya coba.)Ini karena mereka bukan tipe kembali konstruktor dan Anda tidak memesan ruang untuk konstruktor dalam memori. Seperti yang Anda lakukan dalam kasus variabel selama deklarasi. Sebagai contoh: jika Anda menulis variabel X sederhana maka kompiler akan menghasilkan kesalahan karena kompiler tidak akan mengerti arti ini. Tetapi ketika Anda menulis Int x; Kemudian kompiler mengetahui bahwa itu tipe variabel data, sehingga akan disediakan ruang untuk variabel.
Kesimpulan: - jadi kesimpulannya adalah karena pengecualian tipe pengembalian tidak akan mendapatkan alamat dalam memori.
sumber
(void)(*fptr)()
mendeklarasikan pointer ke fungsi tanpa nilai balik.Saya akan menebak:
Konstruktor dan destruktor C ++ sama sekali tidak berfungsi: semuanya makro. Mereka masuk ke dalam ruang lingkup di mana objek dibuat, dan ruang lingkup di mana objek dihancurkan. Pada gilirannya, tidak ada konstruktor atau destruktor, objek hanya IS.
Sebenarnya, saya pikir fungsi-fungsi lain di dalam kelas juga bukan fungsi, tetapi fungsi sebaris yang DONT dapatkan sebaris karena Anda mengambil alamatnya (kompiler menyadari Anda ke dalamnya dan tidak inline atau inline kode ke dalam fungsi dan mengoptimalkan fungsi itu) dan pada gilirannya fungsi tersebut tampaknya "masih ada", meskipun tidak jika Anda belum mengatasinya.
Tabel virtual "objek" C ++ tidak seperti objek JavaScript, di mana Anda bisa mendapatkan konstruktornya dan membuat objek darinya saat runtime via
new XMLHttpRequest.constructor
, melainkan kumpulan pointer ke fungsi anonim yang bertindak sebagai alat untuk berinteraksi dengan objek ini , tidak termasuk kemampuan untuk membuat objek. Dan itu bahkan tidak masuk akal untuk "menghapus" objek, karena itu seperti mencoba untuk menghapus struct, Anda tidak bisa: itu hanya label tumpukan, hanya menulis kepadanya sesuka Anda di bawah label lain: Anda bebas untuk gunakan kelas sebagai 4 bilangan bulat:Tidak ada kebocoran memori, tidak ada masalah, kecuali Anda secara efektif membuang banyak ruang stack yang disediakan untuk antarmuka objek dan string, tetapi itu tidak akan merusak program Anda (selama Anda tidak mencoba menggunakannya) sebagai string lagi).
Sebenarnya, jika asumsi saya sebelumnya benar: biaya lengkap string hanyalah biaya menyimpan 32 byte ini dan ruang string konstan: fungsi hanya digunakan pada waktu kompilasi, dan mungkin juga bisa digarisbawahi dan dibuang setelah objek dibuat dan digunakan (Seolah-olah Anda bekerja dengan struct dan hanya merujuk secara langsung tanpa panggilan fungsi, tentu ada panggilan duplikat alih-alih fungsi melompat, tetapi ini biasanya lebih cepat dan menggunakan lebih sedikit ruang). Intinya, setiap kali Anda memanggil fungsi apa pun, kompiler hanya mengganti panggilan itu dengan instruksi untuk benar-benar melakukannya, dengan pengecualian yang telah ditetapkan oleh perancang bahasa.
Ringkasan: objek C ++ tidak tahu apa itu; semua alat untuk berinteraksi dengan mereka diuraikan secara statis, dan hilang saat runtime. Ini membuat bekerja dengan kelas seefisien mengisi struct dengan data, dan langsung bekerja dengan data itu tanpa memanggil fungsi apa pun (fungsi-fungsi ini diuraikan).
Ini benar-benar berbeda dari pendekatan COM / ObjectiveC serta javascript, yang mempertahankan jenis informasi secara dinamis, dengan biaya runtime overhead, manajemen memori, panggilan konstruksi, karena kompiler tidak dapat membuang informasi ini: diperlukan untuk pengiriman dinamis. Ini pada gilirannya memberi kita kemampuan untuk "Bicara" ke program kami saat runtime, dan mengembangkannya saat sedang berjalan dengan memiliki komponen yang dapat dipantulkan.
sumber
struct { int size; const char * data; };
(sepertinya Anda anggap) Anda menulis 4 * 4 Bytes = 16 byte pada alamat memori di mana Anda hanya memesan 8 byte pada mesin x86, jadi 8 byte dituliskan di atas data lain (yang dapat merusak tumpukan Anda ). Untungnya,std::string
biasanya memiliki beberapa optimasi di tempat untuk string pendek, jadi itu harus cukup besar untuk contoh Anda saat menggunakan beberapa implementasi std utama.