virtual
Fungsi murni harus diimplementasikan dalam tipe turunan yang akan langsung dipakai, namun tipe dasar masih dapat mendefinisikan implementasi. Kelas turunan dapat secara eksplisit memanggil implementasi kelas dasar (jika izin akses mengizinkannya) dengan menggunakan nama dengan cakupan penuh (dengan memanggil A::f()
dalam contoh Anda - jika A::f()
ada public
atau protected
). Sesuatu seperti:
class B : public A {
virtual void f() {
// class B doesn't have anything special to do for f()
// so we'll call A's
// note that A's declaration of f() would have to be public
// or protected to avoid a compile time problem
A::f();
}
};
Kasus penggunaan yang dapat saya pikirkan di atas kepala saya adalah ketika ada perilaku default yang lebih atau kurang masuk akal, tetapi desainer kelas ingin bahwa perilaku semacam standar dipanggil hanya secara eksplisit. Ini juga bisa menjadi kasus yang Anda inginkan kelas turunan untuk selalu melakukan pekerjaan mereka sendiri tetapi juga dapat memanggil serangkaian fungsi umum.
Perhatikan bahwa meskipun diizinkan oleh bahasa, itu bukan sesuatu yang saya lihat umum digunakan (dan fakta bahwa hal itu dapat dilakukan tampaknya mengejutkan sebagian besar programmer C ++, bahkan yang berpengalaman).
deported
. (baik dalam .inl atau .cpp untuk merujuk pada praktik penamaan file yang umum).Agar jelas, Anda salah paham apa = 0; setelah fungsi virtual berarti.
= 0 berarti kelas turunan harus menyediakan implementasi, bukan kelas dasar tidak dapat menyediakan implementasi.
Dalam praktiknya, ketika Anda menandai fungsi virtual sebagai murni (= 0), ada sangat sedikit gunanya dalam memberikan definisi, karena definisi tersebut tidak akan pernah dipanggil kecuali seseorang secara eksplisit melakukannya melalui Base :: Function (...) atau jika Konstruktor kelas dasar memanggil fungsi virtual yang dimaksud.
sumber
Keuntungannya adalah ia memaksa tipe turunan untuk tetap menimpa metode tetapi juga menyediakan implementasi standar atau tambahan.
sumber
Jika Anda memiliki kode yang harus dieksekusi oleh kelas turunan, tetapi Anda tidak ingin kode itu dieksekusi secara langsung - dan Anda ingin memaksanya untuk ditimpa.
Kode Anda benar, meskipun semuanya ini bukan fitur yang sering digunakan, dan biasanya hanya terlihat ketika mencoba mendefinisikan destruktor virtual murni - dalam hal ini Anda harus menyediakan implementasi. Yang lucu adalah bahwa sekali Anda berasal dari kelas itu, Anda tidak perlu menimpa destruktor.
Oleh karena itu, penggunaan fungsi virtual murni yang masuk akal adalah menentukan destruktor virtual murni sebagai kata kunci "non-final".
Kode berikut ini ternyata benar:
sumber
Anda harus memberikan tubuh ke destruktor virtual murni, misalnya :)
Baca: http://cplusplus.co.il/2009/08/22/pure-virtual-destructor/
(Tautan rusak, gunakan arsip)
sumber
Ya ini benar. Dalam contoh Anda, kelas yang berasal dari A mewarisi antarmuka f () dan implementasi default. Tapi Anda memaksa kelas turunan untuk mengimplementasikan metode f () (bahkan jika itu hanya untuk memanggil implementasi default yang disediakan oleh A).
Scott Meyers membahas hal ini dalam C ++ Efektif (Edisi ke-2) Item # 36 Bedakan antara pewarisan antarmuka dan pewarisan implementasi. Nomor item mungkin telah berubah di edisi terbaru.
sumber
Fungsi virtual murni dengan atau tanpa tubuh hanya berarti bahwa tipe turunan harus menyediakan implementasi mereka sendiri.
Badan fungsi virtual murni di kelas dasar berguna jika kelas turunan Anda ingin memanggil implementasi kelas dasar Anda.
sumber
The 'virtual void foo () = 0;' sintaks tidak berarti Anda tidak dapat mengimplementasikan foo () di kelas saat ini, Anda bisa. Ini juga tidak berarti Anda harus mengimplementasikannya di kelas turunan . Sebelum Anda menampar saya, mari kita amati Masalah Intan: (Kode implisit, ingatlah).
Sekarang, permohonan obj-> foo () akan menghasilkan B :: foo () dan kemudian C :: bar ().
Anda lihat ... metode virtual murni tidak harus diimplementasikan di kelas turunan (foo () tidak memiliki implementasi di kelas C - kompiler akan dikompilasi) Di C ++ ada banyak celah.
Semoga saya bisa membantu :-)
sumber
C
dalam contoh Anda. Anda bisa instantiate objek tipeD
karena mendapat implementasifoo
dariB
.Salah satu kasus penggunaan penting memiliki metode virtual murni dengan badan implementasi , adalah ketika Anda ingin memiliki kelas abstrak, tetapi Anda tidak memiliki metode yang tepat di kelas untuk menjadikannya virtual murni. Dalam hal ini, Anda dapat membuat destruktor kelas virtual murni dan meletakkan implementasi yang Anda inginkan (bahkan sebuah badan kosong) untuk itu. Sebagai contoh:
Teknik ini, membuat
Foo
kelas abstrak dan sebagai hasilnya tidak mungkin untuk membuat instance kelas secara langsung. Pada saat yang sama Anda belum menambahkan metode virtual murni tambahan untuk membuatFoo
abstrak kelas.sumber