Dengan definisi struct yang diberikan di bawah ini ...
struct A {
virtual void hello() = 0;
};
Pendekatan # 1:
struct B : public A {
virtual void hello() { ... }
};
Pendekatan # 2:
struct B : public A {
void hello() { ... }
};
Apakah ada perbedaan antara kedua cara ini untuk mengesampingkan fungsi halo?
c++
overriding
virtual-functions
Anarki
sumber
sumber
Jawaban:
Mereka persis sama. Tidak ada perbedaan di antara mereka selain bahwa pendekatan pertama membutuhkan lebih banyak mengetik dan berpotensi lebih jelas.
sumber
override
kata kunci.'Virtualness' suatu fungsi disebarkan secara implisit, namun setidaknya satu kompiler yang saya gunakan akan menghasilkan peringatan jika
virtual
kata kunci tidak digunakan secara eksplisit, jadi Anda mungkin ingin menggunakannya jika hanya untuk membuat kompiler tetap diam.Dari sudut pandang murni gaya, termasuk
virtual
kata kunci jelas 'mengiklankan' fakta kepada pengguna bahwa fungsi ini virtual. Ini akan penting bagi siapa pun yang lebih lanjut mengelompokkan B tanpa harus memeriksa definisi A. Untuk hierarki kelas yang dalam, ini menjadi sangat penting.sumber
Kata
virtual
kunci tidak diperlukan di kelas turunan. Berikut dokumentasi pendukung, dari C ++ Draft Standard (N3337) (tambang penekanan):sumber
Tidak,
virtual
kata kunci pada penggantian fungsi virtual kelas turunan tidak diperlukan. Tetapi perlu disebutkan jebakan terkait: kegagalan untuk menimpa fungsi virtual.The kegagalan untuk override terjadi jika Anda berniat untuk menimpa fungsi virtual di kelas turunan, tetapi membuat kesalahan dalam tanda tangan sehingga menyatakan fungsi virtual yang baru dan berbeda. Fungsi ini mungkin kelebihan fungsi kelas dasar, atau mungkin berbeda namanya. Apakah Anda menggunakan
virtual
kata kunci dalam deklarasi fungsi kelas turunan, kompiler tidak akan dapat memberi tahu bahwa Anda bermaksud menimpa fungsi dari kelas dasar.Perangkap ini, bagaimanapun, untungnya ditangani oleh fitur bahasa override eksplisit C ++ 11 , yang memungkinkan kode sumber untuk secara jelas menentukan bahwa fungsi anggota dimaksudkan untuk menimpa fungsi kelas dasar:
Kompiler akan mengeluarkan kesalahan waktu kompilasi dan kesalahan pemrograman akan segera jelas (mungkin fungsi dalam Derived seharusnya diambil
float
sebagai argumen).Lihat WP: C ++ 11 .
sumber
Menambahkan kata kunci "virtual" adalah praktik yang baik karena meningkatkan keterbacaan, tetapi tidak perlu. Fungsi dinyatakan virtual di kelas dasar, dan memiliki tanda tangan yang sama di kelas turunan dianggap "virtual" secara default.
sumber
Tidak ada perbedaan untuk kompiler, ketika Anda menulis
virtual
di kelas turunan atau menghilangkannya.Tetapi Anda perlu melihat kelas dasar untuk mendapatkan informasi ini. Karena itu saya akan merekomendasikan untuk menambahkan
virtual
kata kunci juga di kelas turunan, jika Anda ingin menunjukkan kepada manusia bahwa fungsi ini virtual.sumber
Ada perbedaan yang cukup besar ketika Anda memiliki template dan mulai mengambil kelas dasar sebagai parameter template:
Bagian yang menyenangkan dari itu adalah bahwa Anda sekarang dapat mendefinisikan fungsi antarmuka dan non-antarmuka nanti untuk mendefinisikan kelas. Itu berguna untuk antarmuka antar kerja antar pustaka (jangan mengandalkan ini sebagai proses desain standar pustaka tunggal ). Anda tidak perlu mengeluarkan biaya apa pun untuk semua kelas Anda - Anda mungkin
typedef
akan mendapatkan sesuatu jika Anda mau.Perhatikan bahwa, jika Anda melakukan ini, Anda mungkin juga ingin mendeklarasikan konstruktor salin / pindahkan sebagai templat: memungkinkan untuk membuat dari antarmuka yang berbeda memungkinkan Anda untuk 'melemparkan' di antara berbagai
B<>
jenis.Ini dipertanyakan apakah Anda harus menambahkan dukungan untuk
const A&
dit_hello()
. Alasan yang biasa untuk penulisan ulang ini adalah untuk beralih dari spesialisasi berbasis warisan ke yang berbasis template, sebagian besar karena alasan kinerja. Jika Anda terus mendukung antarmuka lama, Anda hampir tidak dapat mendeteksi (atau menghalangi) penggunaan lama.sumber
Kata
virtual
kunci harus ditambahkan ke fungsi dari kelas dasar untuk membuatnya dapat ditimpa. Dalam contoh Anda,struct A
adalah kelas dasar.virtual
tidak ada artinya untuk menggunakan fungsi-fungsi tersebut di kelas turunan. Namun, jika Anda ingin kelas turunan Anda juga menjadi kelas dasar itu sendiri, dan Anda ingin fungsi itu dapat ditimpa, maka Anda harus meletakkannya divirtual
sana.Di sini diturunkan
C
dariB
, jadiB
bukan kelas dasar (itu juga kelas turunan), danC
kelas turunan. Diagram warisan terlihat seperti ini:Jadi Anda harus meletakkan
virtual
di depan fungsi di dalam kelas dasar potensial yang mungkin memiliki anak.virtual
memungkinkan anak-anak Anda untuk mengesampingkan fungsi Anda. Tidak ada yang salah dengan menempatkan fungsivirtual
di depan dalam kelas turunan, tetapi tidak diperlukan. Namun disarankan, karena jika seseorang ingin mewarisi dari kelas turunan Anda, mereka tidak akan senang bahwa metode penimpaan tidak berfungsi seperti yang diharapkan.Jadi letakkan
virtual
di depan fungsi di semua kelas yang terlibat dalam warisan, kecuali Anda tahu pasti bahwa kelas tidak akan memiliki anak yang perlu mengganti fungsi kelas dasar. Ini praktik yang bagus.sumber
Saya pasti akan memasukkan kata kunci Virtual untuk kelas anak, karena
sumber