Kelas bertingkat sama seperti kelas reguler, tetapi:
- mereka memiliki batasan akses tambahan (seperti semua definisi di dalam definisi kelas lakukan),
- mereka tidak mencemari namespace yang diberikan , misalnya namespace global. Jika Anda merasa bahwa kelas B terhubung sangat dalam ke kelas A, tetapi objek A dan B belum tentu terkait, maka Anda mungkin ingin kelas B hanya dapat diakses melalui pelingkupan kelas A (itu akan disebut sebagai A ::Kelas).
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 kelas Element
. Anda kemudian dapat:
mendeklarasikan dua kelas: SomeSpecificCollection
dan Element
- buruk, karena nama "Elemen" cukup umum untuk menyebabkan kemungkinan bentrokan nama
mengenalkan namespace someSpecificCollection
dan mendeklarasikan kelas someSpecificCollection::Collection
dan someSpecificCollection::Element
. Tidak ada risiko bentrokan nama, tetapi bisakah itu mendapatkan lebih banyak kata-kata?
mendeklarasikan dua kelas global SomeSpecificCollection
dan SomeSpecificCollectionElement
- yang memiliki kelemahan kecil, tetapi mungkin OK.
mendeklarasikan kelas SomeSpecificCollection
dan kelas global Element
sebagai kelas bersarangnya. Kemudian:
- Anda tidak mengambil risiko bentrokan nama apa pun karena Elemen tidak ada dalam ruang nama global,
- dalam implementasi
SomeSpecificCollection
Anda merujuk ke adil Element
, dan di tempat lain sebagai SomeSpecificCollection::Element
- yang terlihat + - sama dengan 3., tetapi lebih jelas
- itu menjadi sederhana bahwa itu "elemen koleksi tertentu", bukan "elemen koleksi tertentu"
- terlihat
SomeSpecificCollection
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:
class Product {
public:
enum ProductType {
FANCY, AWESOME, USEFUL
};
enum ProductBoxType {
BOX, BAG, CRATE
};
Product(ProductType t, ProductBoxType b, String name);
// the rest of the class: fields, methods
};
Satu kemudian akan memanggil:
Product p(Product::FANCY, Product::BOX);
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:
class Product {
public:
struct ProductType {
enum Enum { FANCY, AWESOME, USEFUL };
};
struct ProductBoxType {
enum Enum { BOX, BAG, CRATE };
};
Product(ProductType::Enum t, ProductBoxType::Enum b, String name);
// the rest of the class: fields, methods
};
Maka panggilan itu terlihat seperti:
Product p(Product::ProductType::FANCY, Product::ProductBoxType::BOX);
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:
class X {
public:
X();
virtual ~X();
void publicInterface();
void publicInterface2();
private:
struct Impl;
std::unique_ptr<Impl> impl;
}
X.cpp:
#include "X.h"
#include <windows.h>
struct X::Impl {
HWND hWnd; // this field is a part of the class, but no need to include windows.h in header
// all private fields, methods go here
void privateMethod(HWND wnd);
void privateMethod();
};
X::X() : impl(new Impl()) {
// ...
}
// and the rest of definitions go here
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
.