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*/}
};