Apa keuntungan membuat metode privat virtual di C ++?
Saya telah memperhatikan ini dalam proyek C ++ open source:
class HTMLDocument : public Document, public CachedResourceClient {
private:
virtual bool childAllowed(Node*);
virtual PassRefPtr<Element> createElement(const AtomicString& tagName, ExceptionCode&);
};
c++
polymorphism
access-specifier
silverburgh
sumber
sumber
Jawaban:
Herb Sutter telah menjelaskannya dengan sangat baik di sini .
Panduan # 2: Lebih suka menjadikan fungsi virtual bersifat pribadi.
Hal ini memungkinkan kelas turunan mengganti fungsi untuk menyesuaikan perilaku sesuai kebutuhan, tanpa mengekspos fungsi virtual lebih jauh secara langsung dengan membuatnya dapat dipanggil oleh kelas turunan (seperti yang mungkin dilakukan jika fungsi hanya dilindungi). Intinya adalah bahwa fungsi virtual ada untuk memungkinkan penyesuaian; kecuali mereka juga perlu dipanggil langsung dari dalam kode kelas turunan, tidak perlu menjadikannya apa pun kecuali pribadi
sumber
Jika metodenya virtual, ia dapat diganti dengan kelas turunan, meskipun itu privat. Saat metode virtual dipanggil, versi yang diganti akan dipanggil.
(Bertentangan dengan Herb Sutter yang dikutip oleh Prasoon Saurav dalam jawabannya, C ++ FAQ Lite merekomendasikan agar virtual pribadi tidak , terutama karena sering membingungkan orang.)
sumber
Terlepas dari semua seruan untuk mendeklarasikan anggota virtual sebagai pribadi, argumen tersebut tidak masuk akal. Seringkali, kelas turunan yang menggantikan fungsi virtual harus memanggil versi kelas dasar. Tidak bisa jika dideklarasikan
private
:Anda harus mendeklarasikan metode kelas dasar
protected
.Kemudian, Anda harus mengambil langkah buruk untuk menunjukkan melalui komentar bahwa metode tersebut harus diganti tetapi tidak dipanggil.
Jadi, pedoman Herb Sutter # 3 ... Tapi kudanya sudah keluar dari kandang.
Saat Anda mendeklarasikan sesuatu,
protected
Anda secara implisit mempercayai penulis kelas turunan mana pun untuk memahami dan menggunakan internal terlindungi dengan benar, seperti halnyafriend
deklarasi menyiratkan kepercayaan yang lebih dalam bagiprivate
anggota.Pengguna yang mendapatkan perilaku buruk karena melanggar kepercayaan itu (misalnya diberi label 'tidak mengerti' dengan tidak repot-repot membaca dokumentasi Anda) hanya menyalahkan diri mereka sendiri.
Pembaruan : Saya memiliki beberapa umpan balik yang mengklaim Anda dapat "merangkai" implementasi fungsi virtual dengan cara ini menggunakan fungsi virtual pribadi. Jika demikian, saya pasti ingin melihatnya.
Kompiler C ++ yang saya gunakan pasti tidak akan membiarkan implementasi kelas turunan memanggil implementasi kelas dasar pribadi.
Jika komite C ++ melonggarkan "pribadi" untuk mengizinkan akses khusus ini, saya akan memilih semua fungsi virtual pribadi. Saat ini, kami masih disarankan untuk mengunci pintu gudang setelah kudanya dicuri.
sumber
set_data
. Instruksim_data = ndata;
dancleanup();
dengan demikian dapat dianggap sebagai invarian yang harus dimiliki untuk semua implementasi. Oleh karena itu jadikancleanup()
non-virtual dan pribadi. Tambahkan panggilan ke metode privat lain yang virtual dan titik ekstensi kelas Anda. Sekarang tidak perlu lagi kelas turunan Anda memanggil basiscleanup()
, kode Anda tetap bersih dan antarmuka Anda sulit digunakan secara tidak benar.cleanup()
s dalam rantai, argumen akan berantakan. Atau apakah Anda merekomendasikan fungsi virtual tambahan untuk setiap turunan dalam rantai? Ick. Bahkan Herb Sutter mengizinkan fungsi virtual yang dilindungi sebagai celah dalam pedomannya # 3. Bagaimanapun, tanpa beberapa kode yang sebenarnya Anda tidak akan pernah meyakinkan saya.Saya pertama kali menemukan konsep ini saat membaca 'Efektif C ++' Scott Meyers, Item 35: Pertimbangkan alternatif untuk fungsi virtual. Saya ingin merujuk Scott Mayers untuk orang lain yang mungkin tertarik.
Ini adalah bagian dari Pola Metode Template melalui idiom Antarmuka Non-Virtual : metode yang dihadapi publik bukanlah virtual; sebaliknya, mereka membungkus panggilan metode virtual yang bersifat pribadi. Kelas dasar kemudian dapat menjalankan logika sebelum dan sesudah panggilan fungsi virtual pribadi:
Saya pikir ini adalah pola desain yang sangat menarik dan saya yakin Anda dapat melihat bagaimana kontrol tambahan berguna.
private
? Alasan terbaiknya adalah kami telah menyediakanpublic
metode menghadapi.protected
agar saya dapat menggunakan metode tersebut untuk hal-hal menarik lainnya? Saya kira itu akan selalu tergantung pada desain Anda dan bagaimana Anda percaya kelas dasar cocok. Saya berpendapat bahwa pembuat kelas turunan harus fokus pada penerapan logika yang diperlukan; yang lainnya sudah diurus. Juga, ada masalah enkapsulasi.Dari perspektif C ++, benar-benar sah untuk menimpa metode virtual pribadi meskipun Anda tidak dapat memanggilnya dari kelas Anda. Ini mendukung desain yang dijelaskan di atas.
sumber
Saya menggunakannya untuk memungkinkan kelas turunan untuk "mengisi kekosongan" untuk kelas dasar tanpa mengekspos lubang seperti itu kepada pengguna akhir. Misalnya, saya memiliki objek yang sangat stateful yang berasal dari basis umum, yang hanya dapat mengimplementasikan 2/3 dari mesin status keseluruhan (kelas turunan menyediakan 1/3 sisanya tergantung pada argumen templat, dan basis tidak dapat menjadi templat untuk alasan lain).
Saya PERLU memiliki kelas dasar umum untuk membuat banyak API publik bekerja dengan benar (saya menggunakan templat variadic), tetapi saya tidak bisa membiarkan objek itu keluar ke alam liar. Lebih buruk lagi, jika saya meninggalkan kawah di mesin negara - dalam bentuk fungsi virtual murni - di mana saja kecuali dalam "Pribadi", saya mengizinkan pengguna yang pandai atau tidak mengerti yang berasal dari salah satu kelas anaknya untuk mengganti metode yang tidak boleh disentuh pengguna. Jadi, saya menempatkan 'otak' mesin negara dalam fungsi virtual PRIVATE. Kemudian turunan langsung dari kelas dasar mengisi kekosongan pada penggantian NON-virtual mereka, dan pengguna dapat dengan aman menggunakan objek yang dihasilkan atau membuat kelas turunan lebih lanjut mereka sendiri tanpa khawatir mengacaukan mesin status.
Adapun argumen bahwa Anda seharusnya tidak MEMILIKI metode virtual publik, saya katakan BS. Pengguna dapat menimpa virtual privat dengan tidak semestinya semudah yang publik- mereka mendefinisikan kelas baru. Jika publik tidak boleh mengubah API tertentu, jangan menjadikannya virtual sama sekali dalam objek yang dapat diakses publik.
sumber