Bagaimana mixin atau sifat-sifat lebih baik daripada pewarisan berganda?

54

C ++ memiliki multiple inheritance, banyak desain bahasa melarangnya berbahaya. Tetapi beberapa bahasa seperti Ruby dan PHP menggunakan sintaks aneh untuk melakukan hal yang sama dan menyebutnya mixin atau traits. Saya mendengar berkali-kali bahwa mixin / traits lebih sulit untuk disalahgunakan daripada multiple inheritance.

Apa yang secara khusus membuat mereka kurang berbahaya? Apakah ada sesuatu yang tidak mungkin dengan mixin / traits tetapi mungkin dengan C ++ - style multiple inheritance? Apakah mungkin mengalami masalah berlian dengan mereka?

Ini seolah-olah kita menggunakan banyak pewarisan tetapi hanya membuat alasan bahwa itu adalah mixin / traits sehingga kita dapat menggunakannya.

Gherman
sumber
7
Menantikan seseorang memposting jawaban yang ditulis dengan baik, bijaksana dan menyeluruh untuk yang satu ini.
Robert Harvey
7
Ruby dan PHP tidak memperkenalkan mixin dan traits. Mixins diperkenalkan di Flavours (1980), Traits diperkenalkan di Squeak Smalltalk (2001). Flavours adalah bahasa berorientasi objek pertama dengan pewarisan berganda, dan menggunakan mixin. C ++ hanya mendapat beberapa warisan dalam versi 2.0, yang dirilis pada tahun 1989, 9 tahun setelah Flavours. Jadi, pertanyaannya seharusnya: Flavours memiliki mixin yang sederhana, tetapi beberapa bahasa seperti C ++ memperkenalkan sintaks aneh untuk melakukan hal yang sama dan menyebutnya multiple inheritance.
Jörg W Mittag

Jawaban:

31

Ada beberapa masalah dengan pewarisan berganda ketika digunakan dengan kelas penuh penuh, tetapi mereka semua berputar di sekitar ambiguitas .

Ambiguitas muncul dalam beberapa cara berbeda:

  1. Jika Anda memiliki dua kelas dasar dengan bidang yang sama x, dan tipe turunan meminta x, apa yang didapatnya?
    • Jika dua xvariabel memiliki tipe yang tidak sesuai, Anda bisa menyimpulkannya.
    • Jika jenisnya sama, Anda bisa mencoba menggabungkannya ke dalam variabel yang sama.
    • Anda selalu bisa mengekspos mereka sebagai nama yang memenuhi syarat aneh dan aneh.
  2. Jika Anda memiliki dua kelas dasar dengan fungsi yang sama fdengan tanda tangan identik, dan seseorang memanggil f, yang dipanggil?
    • Bagaimana jika dua kelas dasar berbagi leluhur virtual yang sama (masalah berlian).
    • Bagaimana jika fungsi tersebut memiliki tanda tangan yang berbeda tetapi kompatibel?
  3. Ketika Anda membangun kelas dengan dua kelas dasar, yang mana dari konstruktor kelas dasar disebut pertama? Ketika Anda menghancurkan objek, yang terbunuh?
  4. Ketika Anda meletakkan objek dalam memori, bagaimana Anda melakukannya secara konsisten?
  5. Bagaimana Anda menangani semua kasus ini dengan 3 kelas dasar? 10?

Dan itu mengabaikan hal-hal seperti pengiriman dinamis, inferensi ketik, pencocokan pola, dan hal-hal lain yang kurang saya ketahui yang menjadi lebih menantang ketika bahasa mendukung banyak pewarisan kelas penuh.

Ciri atau Campuran (atau antarmuka, atau ...) adalah semua konstruksi yang secara khusus membatasi kemampuan jenis sehingga tidak ada ambiguitas. Mereka jarang memiliki apa pun sendiri. Ini memungkinkan komposisi tipe menjadi lebih lancar karena tidak ada dua variabel atau dua fungsi ... ada variabel dan referensi; fungsi dan tanda tangan. Kompiler tahu apa yang harus dilakukan.

Pendekatan umum lainnya yang diambil adalah memaksa pengguna untuk "membangun" (atau mencampur) tipe mereka satu per satu. Alih-alih kelas dasar menjadi mitra yang sama dalam tipe baru, Anda menambahkan satu tipe ke yang lain - menimpa apa pun yang ada di sana (biasanya dengan sintaks opsional untuk menamai ulang dan / atau mengekspos ulang bit yang diganti).

Apakah ada sesuatu yang tidak mungkin dengan mixin / traits tetapi mungkin dengan C ++ - style multiple inheritance?

Tergantung pada bahasanya - umumnya menjadi merepotkan atau tidak mungkin untuk menggabungkan implementasi fungsi dan penyimpanan untuk variabel dari beberapa kelas dasar dan mengeksposnya dalam tipe turunan.

Apakah mungkin mengalami masalah berlian dengan mereka?

Terkadang variasi yang kurang parah akan muncul berdasarkan bahasa Anda, tetapi biasanya tidak. Seluruh sifat dari sifat-sifat tersebut adalah untuk memecahkan ambiguitas semacam itu.

Telastyn
sumber
Bisakah Anda memberi saya contoh bahasa / teknologi yang memungkinkan jenis "bangunan" seperti itu untuk contoh?
Gherman
@ jerman - Saya tentu saja bukan ahli Scala, tetapi pemahaman saya adalah apa yang dilakukan withkata kunci di sana.
Telastyn
"membangun yang secara spesifik membatasi kemampuan tipe sehingga tidak ada ambiguitas": batas seperti apa? Antarmuka tidak memiliki variabel, jadi itu satu batas, tetapi sifat-sifat Scala dan modul Ruby lakukan. Apakah mereka dibatasi dengan cara lain?
David Moles
@ Davidvidoles - itulah cara yang umum, saya juga melihat batasan pada aturan pengiriman virtual (pikirkan antarmuka yang diimplementasikan secara eksplisit oleh C #).
Telastyn