Dapatkah seseorang tolong tunjukkan saya pada beberapa sumber yang bagus untuk memahami dan menggunakan kelas bersarang? Saya memiliki beberapa materi seperti Prinsip-prinsip Pemrograman dan hal-hal seperti Pusat Pengetahuan IBM ini - Kelas Bertingkat
Tapi saya masih kesulitan memahami tujuan mereka. Bisakah seseorang tolong saya?
c++
nested
inner-classes
berkaca mata
sumber
sumber
typedef
. 3. karena mereka menambahkan tingkat tambahan lekukan dalam lingkungan di mana menghindari antrean panjang sudah sulit 4. karena Anda menyatakan dua benda konseptual terpisah dalam satuclass
deklarasi, dllJawaban:
Kelas bersarang itu keren untuk menyembunyikan detail implementasi.
Daftar:
Di sini saya tidak ingin mengekspos Node karena orang lain mungkin memutuskan untuk menggunakan kelas dan itu akan menghalangi saya untuk memperbarui kelas saya karena apa pun yang terpapar adalah bagian dari API publik dan harus dipertahankan selamanya . Dengan menjadikan kelas privat, saya tidak hanya menyembunyikan implementasinya, saya juga mengatakan ini milik saya dan saya dapat mengubahnya kapan saja sehingga Anda tidak dapat menggunakannya.
Lihatlah
std::list
ataustd::map
mereka semua mengandung kelas tersembunyi (atau apakah mereka?). Intinya adalah mereka mungkin atau mungkin tidak, tetapi karena implementasinya bersifat pribadi dan tersembunyi, pembangun STL dapat memperbarui kode tanpa mempengaruhi bagaimana Anda menggunakan kode, atau meninggalkan banyak bagasi lama tergeletak di sekitar STL karena mereka membutuhkan untuk mempertahankan kompatibilitas dengan beberapa orang bodoh yang memutuskan mereka ingin menggunakan kelas Node yang tersembunyi di dalamnyalist
.sumber
Node
seharusnya tidak diekspos di file header sama sekali.detail
konvensi: Alih-alih bergantung pada konvensi semacam itu yang perlu diingat sendiri, lebih baik bergantung pada kompiler yang melacaknya untuk Anda.Kelas bertingkat sama seperti kelas reguler, tetapi:
Beberapa contoh:
Kelas bersarang di depan umum untuk memasukkannya ke dalam lingkup kelas yang relevan
Asumsikan Anda ingin memiliki kelas
SomeSpecificCollection
yang akan mengagregasi objek kelasElement
. Anda kemudian dapat:mendeklarasikan dua kelas:
SomeSpecificCollection
danElement
- buruk, karena nama "Elemen" cukup umum untuk menyebabkan kemungkinan bentrokan namamengenalkan namespace
someSpecificCollection
dan mendeklarasikan kelassomeSpecificCollection::Collection
dansomeSpecificCollection::Element
. Tidak ada risiko bentrokan nama, tetapi bisakah itu mendapatkan lebih banyak kata-kata?mendeklarasikan dua kelas global
SomeSpecificCollection
danSomeSpecificCollectionElement
- yang memiliki kelemahan kecil, tetapi mungkin OK.mendeklarasikan kelas
SomeSpecificCollection
dan kelas globalElement
sebagai kelas bersarangnya. Kemudian:SomeSpecificCollection
Anda merujuk ke adilElement
, dan di tempat lain sebagaiSomeSpecificCollection::Element
- yang terlihat + - sama dengan 3., tetapi lebih jelasSomeSpecificCollection
juga kelas.Menurut pendapat saya, varian terakhir pasti yang paling intuitif dan karenanya desain terbaik.
Biarkan saya tekankan - Ini bukan perbedaan besar dari membuat dua kelas global dengan lebih banyak nama bertele-tele. Itu hanya detail kecil, tapi itu membuat kode lebih jelas.
Memperkenalkan lingkup lain di dalam lingkup kelas
Ini sangat berguna untuk memperkenalkan typedef atau enum. Saya hanya akan memposting contoh kode di sini:
Satu kemudian akan memanggil:
Tetapi ketika melihat proposal penyelesaian kode untuk
Product::
, seseorang akan sering mendapatkan semua nilai enum yang mungkin (KOTAK, FANCY, CRATE) terdaftar dan mudah untuk membuat kesalahan di sini (C ++ 0x jenis enum yang sangat diketik dari penyelesaian itu, tapi tidak apa-apa ).Tetapi jika Anda memperkenalkan ruang lingkup tambahan untuk enum yang menggunakan kelas bersarang, hal-hal bisa terlihat seperti:
Maka panggilan itu terlihat seperti:
Kemudian dengan mengetikkan
Product::ProductType::
IDE, seseorang hanya akan mendapatkan enum dari cakupan yang diinginkan. Ini juga mengurangi risiko melakukan kesalahan.Tentu saja ini mungkin tidak diperlukan untuk kelas kecil, tetapi jika seseorang memiliki banyak enum, maka itu membuat segalanya lebih mudah bagi pemrogram klien.
Dengan cara yang sama, Anda bisa "mengatur" sejumlah besar typedef dalam sebuah template, jika Anda pernah membutuhkannya. Terkadang ini merupakan pola yang bermanfaat.
Ungkapan PIMPL
PIMPL (kependekan dari Pointer to IMPLementation) adalah ungkapan yang berguna untuk menghapus detail implementasi suatu kelas dari header. Ini mengurangi kebutuhan mengkompilasi ulang kelas tergantung pada header kelas 'setiap kali bagian "implementasi" dari header berubah.
Ini biasanya diimplementasikan menggunakan kelas bersarang:
Xh:
X.cpp:
Ini sangat berguna jika definisi kelas penuh membutuhkan definisi jenis dari beberapa perpustakaan eksternal yang memiliki file header yang berat atau hanya jelek (ambil WinAPI). Jika Anda menggunakan PIMPL, maka Anda dapat menyertakan fungsionalitas khusus WinAPI hanya di
.cpp
dan tidak pernah memasukkannya ke dalam.h
.sumber
struct Impl; std::auto_ptr<Impl> impl;
Kesalahan ini dipopulerkan oleh Herb Sutter. Jangan gunakan auto_ptr pada tipe yang tidak lengkap, atau setidaknya lakukan tindakan pencegahan untuk menghindari kesalahan kode yang dihasilkan.auto_ptr
tipe tidak lengkap di sebagian besar implementasi tetapi secara teknis itu adalah UB tidak seperti beberapa templat di C ++ 0x (misalnyaunique_ptr
) di mana telah dibuat eksplisit bahwa parameter templat mungkin tipe yang tidak lengkap dan di mana tepatnya tipe tersebut harus lengkap. (mis. penggunaan~unique_ptr
)T
dariunique_ptr
mungkin tipe yang tidak lengkap."enum class
.Saya tidak menggunakan kelas bersarang banyak, tapi saya menggunakannya sekarang dan kemudian. Terutama ketika saya mendefinisikan beberapa tipe data, dan saya kemudian ingin mendefinisikan functor STL yang dirancang untuk tipe data itu.
Misalnya, pertimbangkan
Field
kelas generik yang memiliki nomor ID, kode tipe, dan nama bidang. Jika saya ingin mencari salah satuvector
dari iniField
dengan nomor ID atau nama, saya mungkin membuat functor untuk melakukannya:Kemudian kode yang perlu dicari ini
Field
dapat menggunakanmatch
cakupan dalamField
kelas itu sendiri:sumber
Seseorang dapat menerapkan pola Builder dengan kelas bersarang . Terutama di C ++, secara pribadi saya merasa lebih bersih secara semantik. Sebagai contoh:
Daripada:
sumber