Apakah "konstruktor objek" nama yang lebih pendek untuk "fungsi dengan nama` objek` jenis kembali `objek`"?

9

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 objecttipe 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 objecttipe 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?

pengguna3123061
sumber
1
Perhatikan bahwa fakta bahwa konstruktor diberi nama berdasarkan jenisnya jauh dari universal: PHP memanggilnya __construct, Object Pascal / Delphi memanggil mereka Create - dan saya sepertinya ingat bahwa dalam kasus itu itu hanya konvensi, dan perbedaan sebenarnya adalah bahwa mereka memiliki kata kunci "konstruktor" di depan definisi mereka.
IMSoP
Catatan: Konstruktor di C ++ tidak mengembalikan apa pun (dan karenanya tidak memiliki jenis pengembalian).
el.pescado
ctors adalah meta-metode, bukan metode. Anda tidak mengirim pesan ctors ke instance kelas, Anda mengirimnya ke kelas - sebenarnya ke objek kelas, yang merupakan meta-objek kelas. dan ctors jelas bukan fungsi, karena mereka memiliki efek samping - Anda mendapatkan hasil yang berbeda setiap kali.

Jawaban:

17

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".

Kevin Fee
sumber
3
Anda juga biasanya tidak menggunakan newuntuk membangun objek di C ++, karena memiliki variabel otomatis.
Quentin
6

Tidak, konstruktor objectsangat berbeda dari fungsi yang dipanggil objectdan kembali object. 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 objectdan menggunakan ekspresi di object()suatu tempat, itu tidak memiliki semantik "panggil konstruktor object." Memiliki semantik "buat objek tipe sementara object." 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:

  1. Panggil fungsi alokasi operator new(yang mengembalikan a void*) untuk mengalokasikan memori mentah untuk objek.
  2. Keluarkan panggilan konstruktor pada memori mentah ini untuk membangun (= menginisialisasi) sebuah objek dalam memori mentah tersebut.

Memikirkan konstruktor objectsebagai fungsi seperti ini:

static object object();

salah. Jika ada, cara konstruktor bekerja lebih dekat dengan ini:

static void object(object &place_to_work_in);

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-baru operator newyang mengembalikan argumennya, diikuti oleh panggilan ke konstruktor (sama seperti ekspresi-baru lainnya).

Angew tidak lagi bangga dengan SO
sumber
Saya akui saya tidak banyak berpartisipasi dalam tumpukan ini, jadi saya mungkin tidak terbiasa dengan budaya dan standar yang diharapkan di sini. Jika ada sesuatu yang dapat saya tingkatkan pada jawaban ini, harap beri tahu saya selain downvoting, sehingga saya dapat memperbaikinya.
Angew tidak lagi bangga dengan SO
+1 Jangan khawatir tentang downvote itu, jawaban Anda hebat :) Untuk beberapa alasan, hampir semua jawaban di sini memiliki satu downvote.
amon
1

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

Konstruktor tidak memiliki nama.

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:

namespace foo { 
    class bar {};
}

foo::bar bar() { return foo::bar(); }

Hal ini tidak benar-benar nama yang sama (fungsi ini hanya bardan kelas adalah foo::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:

class foo {
public:
   foo (int) {}
   foo operator+(foo const &other) {}
};

... lalu kode seperti:

foo f(1);

foo h(0);
h = f + 1;

... dapat membuat objek foo sementara dari 1sehingga dapat meneruskan objek foo itu ke foo::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.

Jerry Coffin
sumber
1

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 nama objek yang mengembalikan objek tipe".

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.

el.pescado
sumber