AFAIK:
C ++ menyediakan tiga jenis polimorfisme.
- Fungsi virtual
- Kelebihan nama fungsi
- Kelebihan operator
Selain tiga jenis polimorfisme di atas, ada jenis polimorfisme lainnya:
- run-time
- waktu kompilasi
- polimorfisme ad-hoc
- polimorfisme parametrik
Saya tahu bahwa polimorfisme runtime dapat dicapai dengan fungsi virtual dan polimorfisme statis dapat dicapai dengan fungsi templat
Tapi untuk dua lainnya
- polimorfisme ad-hoc
- polimorfisme parametrik situs web mengatakan ,
polimorfisme ad-hoc:
Jika kisaran jenis aktual yang dapat digunakan terbatas dan kombinasi harus ditentukan secara individual sebelum digunakan, ini disebut polimorfisme ad-hoc.
polimorfisme parametrik:
Jika semua kode ditulis tanpa menyebutkan jenis tertentu dan dengan demikian dapat digunakan secara transparan dengan sejumlah jenis baru itu disebut parametrik polimorfisme.
Saya hampir tidak bisa memahaminya :(
adakah yang bisa menjelaskan keduanya jika memungkinkan dengan sebuah contoh? Saya berharap jawaban atas pertanyaan ini akan membantu banyak lulus baru dari perguruan tinggi mereka.
sumber
Jawaban:
Memahami / persyaratan untuk polimorfisme
Untuk memahami polimorfisme - seperti istilah yang digunakan dalam Ilmu Komputer - itu membantu untuk memulai dari tes sederhana untuk dan definisi itu. Mempertimbangkan:
Di sini,
f()
adalah untuk melakukan beberapa operasi dan diberi nilaix
dany
sebagai input.Mekanisme C ++ untuk polimorfisme
Polimorfisme khusus yang ditentukan oleh programmer
Anda dapat menulis
f()
sedemikian rupa sehingga dapat beroperasi pada banyak jenis dengan salah satu cara berikut:Preprocessing:
Overloading:
Templat:
Pengiriman virtual:
Mekanisme terkait lainnya
Polimorfisme yang disediakan oleh kompiler untuk tipe bawaan, Konversi standar, dan casting / paksaan dibahas nanti untuk kelengkapan sebagai:
Terminologi
Kategorisasi lebih lanjut
Dengan adanya mekanisme polimorfik di atas, kita dapat mengategorikannya dengan berbagai cara:
Kapan kode khusus tipe polimorfik dipilih?
f
atas denganint
argumen - tergantung pada mekanisme polimorfik yang digunakan dan pilihan inlining yang mungkin dihindari oleh pembuat kompilerf(double)
, atau kode yang dihasilkan mungkin dibuang pada titik tertentu dalam kompilasi atau penautan. ( semua mekanisme di atas kecuali pengiriman virtual )Jenis apa yang didukung?
Arti parametrik Anda hanya dapat mencoba menggunakan fungsi untuk berbagai jenis parameter tanpa secara khusus melakukan apa pun untuk mengaktifkan dukungannya bagi mereka (misalnya templat, makro). Objek dengan fungsi / operator yang bertindak seperti templat / makro mengharapkan 1 adalah semua yang dibutuhkan templat / makro untuk melakukan tugasnya, dengan tipe yang tepat tidak relevan. "Konsep" yang diperkenalkan oleh C ++ 20 mengekspresikan dan menegakkan harapan tersebut - lihat halaman cppreference di sini .
Polimorfisme parametrik memberikan ketikan bebek - sebuah konsep yang dikaitkan dengan James Whitcomb Riley yang tampaknya berkata "Ketika saya melihat seekor burung yang berjalan seperti bebek dan berenang seperti bebek dan dukun seperti bebek, saya menyebut burung itu bebek." .
Subtype (alias inklusi) polimorfisme memungkinkan Anda untuk bekerja pada tipe baru tanpa memperbarui algoritma / fungsi, tetapi mereka harus diturunkan dari kelas dasar yang sama (pengiriman virtual)
1 - Template sangat fleksibel. SFINAE (lihat juga
std::enable_if
) secara efektif memungkinkan beberapa rangkaian harapan untuk polimorfisme parametrik. Misalnya, Anda dapat menyandikan bahwa ketika tipe data yang Anda proses memiliki.size()
anggota Anda akan menggunakan satu fungsi, jika tidak, fungsi lain yang tidak perlu.size()
(tetapi mungkin menderita dalam beberapa cara - misalnya menggunakan yang lebih lambatstrlen()
atau tidak mencetak sebagai berguna pesan dalam log). Anda juga dapat menentukan perilaku ad-hoc ketika template dibuat dengan parameter tertentu, baik meninggalkan beberapa parameter parametrik ( spesialisasi template parsial ) atau tidak ( spesialisasi penuh )."Polimorfik"
Alf Steinbach berkomentar bahwa dalam C ++ Standard polymorphic hanya mengacu pada run-time polymorphism menggunakan virtual dispatch. General Comp. Sci. artinya lebih inklusif, sesuai dengan C ++ glosarium pencipta Bjarne Stroustrup ( http://www.stroustrup.com/glossary.html ):
Jawaban ini - seperti pertanyaannya - menghubungkan fitur-fitur C ++ ke Comp. Sci. terminologi.
Diskusi
Dengan C ++ Standard menggunakan definisi sempit "polimorfisme" daripada Comp. Sci. komunitas, untuk memastikan saling pengertian bagi audiens Anda pertimbangkan ...
Namun, apa yang penting untuk menjadi programmer C ++ yang hebat adalah memahami apa yang sebenarnya dilakukan polimorfisme untuk Anda ...
memungkinkan Anda menulis kode "algoritmik" satu kali dan kemudian menerapkannya ke banyak jenis data
... dan kemudian sangat sadar bagaimana mekanisme polimorfik yang berbeda sesuai dengan kebutuhan Anda yang sebenarnya.
Setelan polimorfisme run-time:
Base*
s,Ketika tidak ada driver yang jelas untuk polimorfisme run-time, opsi waktu kompilasi lebih disukai. Mempertimbangkan:
__FILE__
,,__LINE__
string concatenation literal dan kemampuan unik makro lainnya (yang tetap jahat ;-))Mekanisme lain yang mendukung polimorfisme
Seperti yang dijanjikan, untuk kelengkapan beberapa topik tambahan dibahas:
Jawaban ini diakhiri dengan diskusi tentang bagaimana kombinasi di atas untuk memberdayakan dan menyederhanakan kode polimorfik - terutama polimorfisme parametrik (template dan makro).
Mekanisme untuk pemetaan ke operasi tipe-spesifik
> Overload yang disediakan compiler implisit
Secara konsep, kompiler membebani banyak operator untuk tipe builtin. Secara konseptual tidak berbeda dari overload yang ditentukan pengguna, tetapi terdaftar karena mudah diabaikan. Misalnya, Anda dapat menambahkan ke
int
dandouble
menggunakan notasi yang samax += 2
dan kompiler menghasilkan:Overloading kemudian meluas ke tipe yang ditentukan pengguna:
Overload yang disediakan oleh kompiler untuk tipe dasar adalah umum dalam bahasa komputer level tinggi (3GL +), dan diskusi eksplisit tentang polimorfisme umumnya menyiratkan sesuatu yang lebih. (2GL - bahasa assembly - sering mengharuskan programmer untuk secara eksplisit menggunakan mnemonik yang berbeda untuk jenis yang berbeda.)
> Konversi standar
Bagian keempat C ++ Standard menjelaskan konversi Standar.
Poin pertama merangkum dengan baik (dari konsep lama - semoga masih secara substansial benar):
Nol atau satu konversi dari rangkaian berikut: konversi lvalue-ke-rvalue, konversi array-ke-pointer, dan konversi fungsi-ke-pointer.
Nol atau satu konversi dari rangkaian berikut: promosi integral, promosi floating point, konversi integral, konversi floating point, konversi floating-integral, konversi pointer, konversi pointer ke anggota, dan konversi boolean.
Nol atau satu konversi kualifikasi.
Konversi ini memungkinkan kode seperti:
Menerapkan tes sebelumnya:
a()
sendiri menjalankan kode khusus untukdouble
dan karena itu bukan polimorfik.Tapi, dalam panggilan kedua ke
a()
kompiler tahu untuk menghasilkan kode yang sesuai jenis untuk "promosi floating point" (Standar §4) untuk dikonversi42
menjadi42.0
. Kode tambahan itu ada dalam fungsi panggilan . Kami akan membahas pentingnya hal ini dalam kesimpulan.> Paksaan, gips, konstruktor implisit
Mekanisme ini memungkinkan kelas yang ditentukan pengguna untuk menentukan perilaku yang mirip dengan konversi standar tipe yang dibangun. Mari kita lihat:
Di sini, objek
std::cin
dievaluasi dalam konteks boolean, dengan bantuan operator konversi. Ini dapat dikelompokkan secara konseptual dengan "promosi integral" dkk dari Konversi standar dalam topik di atas.Konstruktor implisit secara efektif melakukan hal yang sama, tetapi dikendalikan oleh tipe cast-to:
Implikasi dari overload, konversi, dan paksaan yang disediakan oleh kompiler
Mempertimbangkan:
Jika kita ingin jumlah
x
diperlakukan sebagai bilangan real selama pembagian (yaitu menjadi 6,5 daripada dibulatkan ke 6), kita hanya perlu mengubah ketypedef double Amount
.Itu bagus, tetapi tidak akan terlalu banyak pekerjaan untuk membuat kode secara eksplisit "ketik benar":
Tetapi, pertimbangkan bahwa kami dapat mengubah versi pertama menjadi
template
:Ini karena "fitur kenyamanan" kecil yang dapat dengan mudah dipakai untuk
int
ataudouble
bekerja sebagaimana dimaksud. Tanpa fitur-fitur ini, kita akan membutuhkan gips yang eksplisit, ketik ciri-ciri dan / atau kelas kebijakan, beberapa kekacauan yang cenderung kesalahan seperti:Jadi, overloading yang disediakan operator compiler untuk tipe builtin, Konversi standar, casting / koersi / konstruktor implisit - mereka semua memberikan dukungan halus untuk polimorfisme. Dari definisi di bagian atas jawaban ini, mereka membahas "menemukan dan mengeksekusi kode yang sesuai jenis" dengan memetakan:
"jauh" dari tipe parameter
dari banyak tipe data menangani kode algoritmik algoritmik polimorfik
untuk kode yang ditulis untuk sejumlah (berpotensi lebih rendah) dari jenis (sama atau lainnya).
"ke" tipe parametrik dari nilai tipe konstan
Mereka tidak membangun konteks polimorfik sendiri, tetapi membantu memberdayakan / menyederhanakan kode di dalam konteks tersebut.
Anda mungkin merasa ditipu ... sepertinya tidak banyak. Signifikansi adalah bahwa dalam konteks polimorfik parametrik (yaitu di dalam template atau makro), kami mencoba untuk mendukung berbagai jenis sewenang-wenang tetapi sering ingin mengekspresikan operasi pada mereka dalam hal fungsi lain, literal dan operasi yang dirancang untuk suatu set kecil jenis. Ini mengurangi kebutuhan untuk membuat fungsi atau data yang hampir identik pada basis per jenis ketika operasi / nilai secara logis sama. Fitur-fitur ini bekerja sama untuk menambah sikap "upaya terbaik", melakukan apa yang secara intuitif diharapkan dengan menggunakan fungsi dan data yang tersedia terbatas dan hanya berhenti dengan kesalahan ketika ada ambiguitas nyata.
Ini membantu membatasi kebutuhan kode polimorfik yang mendukung kode polimorfik, menarik jaring yang lebih ketat di sekitar penggunaan polimorfisme sehingga penggunaan yang terlokalisasi tidak memaksa penggunaan yang luas, dan membuat manfaat polimorfisme tersedia sesuai kebutuhan tanpa membebankan biaya karena harus mengekspos implementasi di mengkompilasi waktu, memiliki banyak salinan dari fungsi logis yang sama dalam kode objek untuk mendukung jenis yang digunakan, dan dalam melakukan pengiriman virtual sebagai lawan inlining atau setidaknya kompilasi waktu penyelesaian panggilan. Seperti biasa dalam C ++, programmer diberi banyak kebebasan untuk mengontrol batas-batas di mana polimorfisme digunakan.
sumber
dynamic_cast
memerlukan "penunjuk ke atau nilai dari tipe polimorfik". Ceria & hth.,Dalam C ++, perbedaan penting adalah run-time vs binding-waktu kompilasi. Ad-hoc vs parametrik tidak terlalu membantu, seperti yang akan saya jelaskan nanti.
Catatan - polimorfisme run-time mungkin masih dapat diselesaikan pada waktu kompilasi, tapi itu hanya optimasi. Perlu untuk mendukung resolusi run-time secara efisien, dan berdagang melawan masalah lain, adalah bagian dari apa yang menyebabkan fungsi virtual menjadi seperti itu. Dan itu benar-benar penting untuk semua bentuk polimorfisme dalam C ++ - masing-masing muncul dari rangkaian pengorbanan berbeda yang dibuat dalam konteks yang berbeda.
Kelebihan fungsi dan kelebihan operator adalah hal yang sama dalam setiap hal yang penting. Nama dan sintaksis untuk menggunakannya tidak memengaruhi polimorfisme.
Templat memungkinkan Anda menentukan banyak fungsi berlebih sekaligus.
Ada serangkaian nama lain untuk ide resolusi-waktu yang sama ...
Nama-nama ini lebih terkait dengan OOP, jadi agak aneh untuk mengatakan bahwa templat atau fungsi non-anggota lainnya menggunakan penjilidan awal.
Untuk lebih memahami hubungan antara fungsi virtual dan fungsi yang berlebihan, penting juga untuk memahami perbedaan antara "pengiriman tunggal" dan "pengiriman ganda". Idenya dapat dipahami sebagai sebuah perkembangan ...
Jelas ada lebih banyak OOP daripada alasan untuk menominasikan satu parameter sebagai istimewa, tetapi itu adalah salah satu bagian darinya. Dan berkaitan dengan apa yang saya katakan tentang pertukaran - pengiriman tunggal cukup mudah dilakukan secara efisien (implementasi yang biasa disebut "tabel virtual"). Pengiriman ganda lebih canggung, tidak hanya dalam hal efisiensi, tetapi juga untuk kompilasi terpisah. Jika Anda penasaran, Anda mungkin mencari "masalah ekspresi".
Sama seperti itu agak aneh untuk menggunakan istilah "pengikatan awal" untuk fungsi non-anggota, itu agak aneh untuk menggunakan istilah "pengiriman tunggal" dan "pengiriman ganda" di mana polimorfisme diselesaikan pada waktu kompilasi. Biasanya, C ++ dianggap tidak memiliki banyak pengiriman, yang dianggap sebagai jenis resolusi run-time tertentu. Namun, fungsi overloading dapat dilihat sebagai pengiriman ganda yang dilakukan pada waktu kompilasi.
Kembali ke polimorfisme parametrik vs ad-hoc, istilah-istilah ini lebih populer dalam pemrograman fungsional, dan mereka tidak cukup berfungsi dalam C ++. Walaupun demikian...
Polimorfisme parametrik berarti bahwa Anda memiliki tipe sebagai parameter, dan kode yang sama persis digunakan terlepas dari tipe apa yang Anda gunakan untuk parameter tersebut.
Polimorfisme ad-hoc adalah ad-hoc dalam arti bahwa Anda memberikan kode yang berbeda tergantung pada jenis tertentu.
Overloading dan fungsi virtual adalah contoh dari polimorfisme ad-hoc.
Sekali lagi, ada beberapa sinonim ...
Kecuali ini bukan sinonim, meskipun mereka umumnya diperlakukan seolah-olah mereka, dan di situlah kebingungan cenderung muncul di C ++.
Alasan di balik memperlakukan ini sebagai sinonim adalah bahwa dengan membatasi polimorfisme untuk kelas tipe tertentu, menjadi mungkin untuk menggunakan operasi khusus untuk kelas tipe tersebut. Kata "kelas" di sini dapat diartikan dalam arti OOP, tetapi sebenarnya hanya merujuk pada (biasanya disebut) set tipe yang berbagi operasi tertentu.
Jadi polimorfisme parametrik biasanya diambil (setidaknya secara default) untuk menyiratkan polimorfisme yang tidak dibatasi. Karena kode yang sama digunakan terlepas dari parameter tipe, satu-satunya operasi yang didukung adalah yang bekerja untuk semua tipe. Dengan membiarkan rangkaian tipe tidak dibatasi, Anda sangat membatasi rangkaian operasi yang dapat Anda terapkan pada tipe tersebut.
Dalam misalnya Haskell, Anda dapat memiliki ...
Di
a
sini adalah tipe polimorfik yang tidak dibatasi. Itu bisa apa saja, jadi tidak banyak yang bisa kita lakukan dengan nilai-nilai dari tipe itu.Di sini,
a
dibatasi untuk menjadi anggotaNum
kelas - tipe yang bertindak seperti angka. Batasan itu memungkinkan Anda untuk melakukan hal-hal nomor dengan nilai-nilai tersebut, seperti menambahkannya. Bahkan3
inferensi tipe polimorfik menunjukkan bahwa yang Anda maksud adalah3
tipea
.Saya menganggap ini sebagai polimorfisme parametrik terbatas. Hanya ada satu implementasi, tetapi hanya bisa diterapkan dalam kasus terbatas. Aspek ad-hoc adalah pilihan yang digunakan
+
dan3
untuk digunakan. Setiap "instance" dariNum
memiliki implementasi yang berbeda dari ini. Jadi, bahkan dalam Haskell "parametrik" dan "tidak dibatasi" tidak benar-benar sinonim - jangan salahkan saya, itu bukan salah saya!Dalam C ++, baik fungsi overloading dan virtual adalah polimorfisme ad-hoc. Definisi polimorfisme ad-hoc tidak peduli apakah implementasinya dipilih saat run-time atau compile-time.
C ++ menjadi sangat dekat dengan polimorfisme parametrik dengan templat jika setiap parameter templat memiliki tipe
typename
. Ada tipe parameter, dan ada implementasi tunggal tidak peduli tipe apa yang digunakan. Namun, aturan "Kegagalan Substitusi Bukan Kesalahan" berarti bahwa kendala implisit muncul sebagai akibat dari penggunaan operasi dalam templat. Komplikasi tambahan termasuk spesialisasi templat untuk menyediakan templat alternatif - implementasi berbeda (ad-hoc).Jadi dengan cara C ++ memiliki polimorfisme parametrik, tetapi secara implisit dibatasi dan dapat ditimpa oleh alternatif ad-hoc - yaitu klasifikasi ini tidak benar-benar berfungsi untuk C ++.
sumber
a
ini adalah tipe polimorfik yang tidak dibatasi [...] sehingga tidak banyak yang bisa kita lakukan dengan nilai-nilai dari tipe itu." sangat menarik - dalam C ++ sans Konsep Anda tidak terbatas hanya mencoba serangkaian operasi tertentu pada argumen dari jenis yang ditentukan sebagai parameter templat ... perpustakaan seperti meningkatkan konsep bekerja dengan cara lain - memastikan jenis mendukung operasi Anda menentukan, alih-alih menjaga agar operasi tambahan tidak disengaja.Adapun polimorfisme ad-hoc, itu berarti overloading fungsi atau overloading operator. Lihat di sini:
http://en.wikipedia.org/wiki/Ad-hoc_polymorphism
Adapun polimorfisme parametrik, fungsi template juga dapat dihitung karena mereka tidak selalu mengambil parameter tipe TETAP. Misalnya, satu fungsi dapat mengurutkan array bilangan bulat dan juga dapat mengurutkan array string, dll.
http://en.wikipedia.org/wiki/Parametric_polymorphism
sumber
<
operator dan sejenisnya). Di Haskell, Anda akan mengungkapkan persyaratan itu secara eksplisit menggunakan kelasOrd
. Fakta bahwa Anda mendapatkan perbedaan<
tergantung pada jenis tertentu (seperti yang disediakan oleh contohOrd
) akan dianggap sebagai polimorfisme ad-hoc.Ini mungkin tidak membantu, tetapi saya membuat ini untuk memperkenalkan teman-teman saya ke pemrograman dengan memberikan fungsi yang didefinisikan, seperti
START
, danEND
untuk fungsi utama sehingga tidak terlalu menakutkan (mereka hanya menggunakan file main.cpp ). Ini berisi kelas dan struct Polymorphic, templates, vektor, array, arahan preproccessor, persahabatan, operator dan pointer (yang semuanya mungkin harus Anda ketahui sebelum mencoba polimorfisme):Catatan: Belum selesai, tetapi Anda bisa mendapatkan ide
main.cpp
main.h
sumber
Berikut adalah contoh dasar menggunakan kelas Polimorfik
sumber
Polimorfisme berarti banyak bentuk seperti itu digunakan untuk operator untuk bertindak berbeda dalam berbagai kasus. Polimorfisme digunakan untuk mengimplementasikan warisan. Sebagai contoh, kita telah mendefinisikan draw fn () untuk bentuk kelas maka draw fn dapat diimplementasikan untuk menggambar lingkaran, kotak, segitiga dan bentuk lainnya. (yang merupakan objek dari bentuk kelas)
sumber
Jika ada yang mengatakan CUT kepada orang-orang ini
Apa yang akan terjadi?
Jadi representasi di atas menunjukkan Apa itu polimorfisme (nama yang sama, perilaku yang berbeda) dalam OOP.
Jika Anda pergi untuk wawancara dan pewawancara meminta Anda memberi tahu / menunjukkan contoh langsung untuk polimorfisme di ruangan yang sama dengan tempat kami duduk, katakan-
Jawab - Pintu / Windows
Bingung Bagaimana?
Melalui Pintu / Jendela - seseorang bisa datang, udara bisa datang, cahaya bisa datang, hujan bisa datang, dll.
yaitu Satu bentuk perilaku yang berbeda (Polimorfisme).
Untuk memahaminya dengan lebih baik dan secara sederhana saya menggunakan contoh di atas .. Jika Anda memerlukan referensi untuk kode ikuti jawaban di atas.
sumber