Saya telah mendengar bahwa templat fungsi anggota kelas C ++ tidak bisa virtual. Apakah ini benar?
Jika mereka bisa virtual, apa contoh skenario di mana seseorang akan menggunakan fungsi seperti itu?
c++
templates
virtual-functions
function-templates
c++-faq
InginBeGeek
sumber
sumber
Jawaban:
Template adalah semua tentang kode penghasil kompiler pada waktu kompilasi . Fungsi virtual adalah semua tentang sistem run-time yang mencari tahu fungsi mana yang harus dipanggil pada saat run-time .
Setelah sistem run-time menemukan itu perlu memanggil fungsi virtual templatized, kompilasi semua dilakukan dan kompiler tidak dapat menghasilkan contoh yang sesuai lagi. Karenanya Anda tidak dapat memiliki templat fungsi anggota virtual.
Namun, ada beberapa teknik yang kuat dan menarik yang berasal dari menggabungkan polimorfisme dan template, terutama yang disebut penghapusan tipe .
sumber
Virtual functions are all about the run-time system figuring out which function to call at run-time
- maaf tapi ini cara yang agak salah, dan cukup membingungkan. Itu hanya tipuan, dan tidak ada "runtime figuring out" yang terlibat, diketahui selama waktu kompilasi bahwa fungsi yang akan dipanggil adalah yang ditunjukkan oleh pointer n-th di vtable. "Mencari tahu" menyiratkan ada pemeriksaan jenis dan semacamnya, yang tidak terjadi.Once the run-time system figured out it would need to call a templatized virtual function
- Apakah fungsinya virtual atau tidak diketahui pada waktu kompilasi.void f(concr_base& cb, virt_base& vb) { cb.f(); vb.f(); }
, maka ia "tahu" fungsi apa yang dipanggil pada titik yangcb.f()
dipanggil, dan tidak tahu itu untukvb.f()
. Yang terakhir harus ditemukan saat runtime , oleh sistem runtime . Apakah Anda ingin menyebutnya "mencari tahu", dan apakah ini lebih atau kurang efisien, tidak sedikit mengubah fakta ini.Dari C ++ Templates Panduan Lengkap:
sumber
C ++ tidak mengizinkan fungsi anggota template virtual sekarang. Alasan yang paling mungkin adalah kompleksitas penerapannya. Rajendra memberikan alasan yang bagus mengapa hal itu tidak dapat dilakukan saat ini tetapi mungkin dengan perubahan standar yang masuk akal. Terutama mengetahui berapa banyak contoh fungsi templated sebenarnya ada dan membangun vtable tampaknya sulit jika Anda mempertimbangkan tempat panggilan fungsi virtual. Orang standar hanya memiliki banyak hal lain yang harus dilakukan sekarang dan C ++ 1x adalah banyak pekerjaan untuk penulis kompiler juga.
Kapan Anda membutuhkan fungsi anggota templated? Saya pernah menemukan situasi seperti itu di mana saya mencoba untuk memperbaiki hierarki dengan kelas dasar virtual murni. Itu adalah gaya yang buruk untuk menerapkan strategi yang berbeda. Saya ingin mengubah argumen dari salah satu fungsi virtual ke tipe numerik dan alih-alih membebani fungsi anggota dan menimpa setiap kelebihan di semua sub-kelas saya mencoba menggunakan fungsi templat virtual (dan harus mencari tahu bahwa itu tidak ada) .)
sumber
Tabel Fungsi Virtual
Mari kita mulai dengan beberapa latar belakang pada tabel fungsi virtual dan cara kerjanya ( sumber ):
Masalah saya, atau bagaimana saya datang ke sini
Saya mencoba menggunakan sesuatu seperti ini sekarang untuk kelas dasar cubefile dengan fungsi beban yang dioptimalkan templated yang akan diimplementasikan secara berbeda untuk berbagai jenis kubus (beberapa disimpan oleh pixel, beberapa oleh gambar, dll).
Beberapa kode:
Apa yang saya inginkan, tetapi tidak dapat dikompilasi karena kombo templated virtual:
Saya akhirnya memindahkan deklarasi templat ke tingkat kelas. Solusi ini akan memaksa program untuk mengetahui tentang tipe data tertentu yang akan mereka baca sebelum membacanya, yang tidak dapat diterima.Larutan
peringatan, ini tidak terlalu cantik tapi itu memungkinkan saya untuk menghapus kode eksekusi berulang
1) di kelas dasar
2) dan di kelas anak-anak
Perhatikan bahwa LoadAnyCube tidak dideklarasikan di kelas dasar.
Berikut jawaban stack overflow lain dengan penyelesaian : perlu solusi anggota template virtual .
sumber
Kode berikut dapat dikompilasi dan dijalankan dengan benar, menggunakan MinGW G ++ 3.4.5 pada Window 7:
dan hasilnya adalah:
Dan kemudian saya menambahkan kelas X baru:
Ketika saya mencoba menggunakan kelas X di main () seperti ini:
g ++ melaporkan kesalahan berikut:
Jadi jelas bahwa:
sumber
Tidak, mereka tidak bisa. Tapi:
memiliki banyak efek yang sama jika semua yang ingin Anda lakukan adalah memiliki antarmuka umum dan menunda implementasi ke subclass.
sumber
Foo
Pointer Anda memenuhi syarat karenaFoo<Bar>
, tidak dapat menunjuk keFoo<Barf>
atauFoo<XXX>
.Tidak, fungsi anggota template tidak boleh virtual.
sumber
Di jawaban lain fungsi templat yang diusulkan adalah fasad dan tidak menawarkan manfaat praktis.
Bahasa tidak memungkinkan fungsi template virtual tetapi dengan solusi dimungkinkan untuk memiliki keduanya, misalnya satu implementasi template untuk setiap kelas dan antarmuka umum virtual.
Namun demikian perlu untuk mendefinisikan untuk setiap kombinasi jenis template fungsi pembungkus virtual dummy:
Keluaran:
Coba di sini
sumber
Untuk menjawab bagian kedua dari pertanyaan:
Ini bukan hal yang tidak masuk akal untuk dilakukan. Misalnya, Java (di mana setiap metode virtual) tidak memiliki masalah dengan metode generik.
Salah satu contoh dalam C ++ menginginkan templat fungsi virtual adalah fungsi anggota yang menerima iterator generik. Atau fungsi anggota yang menerima objek fungsi generik.
Solusi untuk masalah ini adalah dengan menggunakan tipe erasure dengan boost :: any_range dan boost :: function, yang akan memungkinkan Anda untuk menerima iterator atau functor generik tanpa perlu menjadikan fungsi Anda sebagai templat.
sumber
Ada solusi untuk 'metode templat virtual' jika rangkaian tipe untuk metode templat diketahui sebelumnya.
Untuk menunjukkan ide, dalam contoh di bawah ini hanya dua jenis yang digunakan (
int
dandouble
).Di sana, metode template 'virtual' (
Base::Method
) memanggil metode virtual yang sesuai (salah satunyaBase::VMethod
) yang, pada gilirannya, memanggil implementasi metode template (Impl::TMethod
).Satu hanya perlu menerapkan metode template
TMethod
dalam implementasi turunan (AImpl
,BImpl
) dan digunakanDerived<*Impl>
.Keluaran:
NB:
Base::Method
sebenarnya surplus untuk kode nyata (VMethod
dapat dibuat publik dan digunakan secara langsung). Saya menambahkannya sehingga terlihat seperti metode template 'virtual' yang sebenarnya.sumber
Base
kelas asli setiap kali Anda perlu memanggil fungsi template dengan tipe argumen yang tidak kompatibel dengan yang diterapkan sejauh ini. Menghindari keharusan ini adalah maksud dari templat ...Sementara pertanyaan yang lebih tua yang telah dijawab oleh banyak orang, saya percaya metode ringkas, tidak begitu berbeda dari yang lain diposting, adalah menggunakan makro kecil untuk membantu memudahkan duplikasi deklarasi kelas.
Jadi sekarang, untuk mengimplementasikan subclass kami:
Manfaatnya di sini adalah, ketika menambahkan jenis yang baru didukung, semuanya dapat dilakukan dari header abstrak dan mengabaikan kemungkinan memperbaikinya dalam beberapa file sumber / header.
sumber
Setidaknya dengan gcc 5.4 fungsi virtual bisa menjadi anggota templat tetapi harus templat sendiri.
Keluaran
sumber
Coba ini:
Tulis di classeder.h:
Periksa, jika bekerja dengan ini, untuk menulis kode ini di main.cpp:
sumber