Pertanyaan dalam topik ini menunjukkan kebingungan yang cukup umum. Kebingungan cukup umum, bahwa C ++ FAQ menganjurkan untuk tidak menggunakan virtual pribadi, untuk waktu yang lama, karena kebingungan tampaknya menjadi hal yang buruk.
Jadi untuk menghilangkan kebingungan terlebih dahulu: Ya, fungsi virtual pribadi dapat ditimpa dalam kelas turunan. Metode kelas turunan tidak dapat memanggil fungsi virtual dari kelas dasar, tetapi mereka dapat memberikan implementasi sendiri untuk mereka. Menurut Herb Sutter, memiliki antarmuka non-virtual publik di kelas dasar dan implementasi pribadi yang dapat dikustomisasi di kelas turunan, memungkinkan untuk lebih baik "pemisahan spesifikasi antarmuka dari spesifikasi perilaku yang dapat disesuaikan implementasi". Anda dapat membaca lebih lanjut tentang itu di artikelnya "Virtualitas" .
Namun ada satu hal lagi yang menarik dalam kode yang Anda presentasikan, yang patut mendapat perhatian lebih, menurut saya. Antarmuka publik terdiri dari serangkaian fungsi non-virtual yang kelebihan beban dan fungsi-fungsi tersebut memanggil fungsi virtual non-publik, non-kelebihan beban. Seperti biasa di dunia C ++ itu adalah idiom, ia memiliki nama dan tentu saja itu berguna. Namanya (kejutan, kejutan!)
"Non-Virtual Call Overloaded Publik Dilindungi Virtual Non-Overloaded"
Ini membantu untuk mengelola aturan persembunyian dengan benar . Anda dapat membaca lebih lanjut tentang ini di sini , tetapi saya akan mencoba menjelaskannya segera.
Bayangkan, bahwa fungsi virtual dari Engine
kelas juga merupakan antarmuka dan itu adalah satu set fungsi kelebihan beban yang bukan virtual murni. Jika mereka murni virtual, orang masih bisa menghadapi masalah yang sama, seperti yang dijelaskan di bawah ini, tetapi lebih rendah dalam hirarki kelas.
class Engine
{
public:
virtual void SetState( int var, bool val ) {/*some implementation*/}
virtual void SetState( int var, int val ) {/*some implementation*/}
};
Sekarang mari kita asumsikan Anda ingin membuat kelas turunan dan Anda perlu menyediakan implementasi baru hanya untuk metode ini, yang menggunakan dua int sebagai argumen.
class MyTurbochargedV8 : public Engine
{
public:
// To prevent SetState( int var, bool val ) from the base class,
// from being hidden by the new implementation of the other overload (below),
// you have to put using declaration in the derived class
using Engine::SetState;
void SetState( int var, int val ) {/*new implementation*/}
};
Jika Anda lupa untuk menempatkan deklarasi penggunaan di kelas turunan (atau untuk mendefinisikan kembali kelebihan kedua), Anda bisa mendapat masalah dalam skenario di bawah ini.
MyTurbochargedV8* myV8 = new MyTurbochargedV8();
myV8->SetState(5, true);
Jika Anda tidak mencegah persembunyian Engine
anggota, pernyataan:
myV8->SetState(5, true);
akan memanggil void SetState( int var, int val )
dari kelas turunan, mengubahnya true
menjadi int
.
Jika antarmuka bukan virtual dan implementasi virtual adalah non-publik, seperti di exmaple Anda, penulis kelas turunan memiliki satu masalah yang kurang untuk dipikirkan dan hanya dapat menulis
class MyTurbochargedV8 : public Engine
{
private:
void SetStateInt(int var, int val ) {/*new implementation*/}
};
Fungsi virtual murni privat adalah dasar dari idiom antarmuka Non-virtual (OK, itu tidak sepenuhnya virtual murni , tetapi masih virtual di sana). Tentu saja, ini digunakan untuk hal-hal lain juga, tetapi saya menemukan ini untuk yang paling berguna (: Dalam dua kata: dalam fungsi publik, Anda bisa meletakkan beberapa hal umum (seperti logging, statistik, dll.) Di awal dan di akhir fungsi dan kemudian, "di tengah" untuk memanggil fungsi virtual pribadi ini, yang akan berbeda untuk kelas turunan tertentu. Sesuatu seperti:
Virtual murni - hanya mewajibkan kelas turunan untuk mengimplementasikannya.
EDIT : Lebih lanjut tentang ini: Wikipedia :: NVI-idiom
sumber
Yah, untuk satu, ini akan memungkinkan kelas turunan untuk mengimplementasikan fungsi yang kelas dasar (berisi deklarasi fungsi virtual murni) dapat memanggil.
sumber
EDIT: Pernyataan yang diklarifikasi tentang kemampuan menimpa dan kemampuan untuk mengakses / memohon.
Ini akan dapat mengesampingkan fungsi-fungsi pribadi tersebut. Sebagai contoh, karya contoh yang dibuat berikut ini ( EDIT: membuat metode kelas turunan pribadi, dan menjatuhkan pemanggilan metode kelas turunan
main()
untuk lebih menunjukkan maksud pola desain yang digunakan. ):Private
virtual
metode di kelas dasar seperti yang ada di kode Anda biasanya digunakan untuk menerapkan pola desain Metode Templat . Pola desain itu memungkinkan seseorang untuk mengubah perilaku suatu algoritma di kelas dasar tanpa mengubah kode di kelas dasar. Kode di atas di mana metode kelas dasar dipanggil melalui pointer kelas dasar adalah contoh sederhana dari pola Metode Templat.sumber
Engine
danDerivedEngine
tidak ada hubungannya dengan apa yangDerivedEngine
bisa atau tidak bisa menimpa (atau akses, dalam hal ini).Metode virtual privat digunakan untuk membatasi jumlah kelas turunan yang dapat mengesampingkan fungsi yang diberikan. Kelas turunan yang harus mengganti metode virtual pribadi harus menjadi teman kelas dasar.
Penjelasan singkat dapat ditemukan dari DevX.com .
EDIT Metode virtual pribadi secara efektif digunakan dalam Pola Metode Template . Kelas turunan dapat mengesampingkan metode virtual pribadi tetapi kelas turunan tidak dapat memanggilnya metode virtual pribadi kelas dasar (dalam contoh Anda,
SetStateBool
danSetStateInt
). Hanya kelas dasar yang dapat secara efektif memanggil metode virtual privatnya ( Hanya jika kelas turunan perlu memohon implementasi dasar dari fungsi virtual, buatlah fungsi virtual terlindungi ).Artikel menarik dapat ditemukan tentang Virtualitas .
sumber
friend
kelas dasar. Qt telah mengambil pendekatan yang sama ketika mereka menerapkan model dokumen XML DOM mereka.TL; DR jawab:
Anda dapat memperlakukannya seperti tingkat enkapsulasi lainnya - di suatu tempat antara dilindungi dan pribadi : Anda tidak dapat memanggilnya dari kelas anak-anak, tetapi Anda dapat menimpanya.
Berguna saat menerapkan pola desain Metode Templat . Anda dapat menggunakan protected , tetapi privat bersama dengan virtual dapat dianggap sebagai pilihan yang lebih baik, karena enkapsulasi yang lebih baik.
sumber