Yuvalanmış sınıflar normal sınıflar gibidir, ancak:
- ek erişim kısıtlamaları vardır (bir sınıf tanımındaki tüm tanımlar gibi),
- Onlar verilen ad kirletmeyen genel ad alanını örneğin,. B sınıfının A sınıfına o kadar derinden bağlı olduğunu düşünüyorsanız, ancak A ve B nesnelerinin ille de ilişkili olmadığını düşünüyorsanız, B sınıfının yalnızca A sınıfının kapsamını kullanarak erişilebilir olmasını isteyebilirsiniz (A olarak adlandırılır. ::Sınıf).
Bazı örnekler:
İlgili sınıfın kapsamına koymak için genel olarak sınıflandırma
Sınıf SomeSpecificCollection
nesnelerini toplayacak bir sınıfa sahip olmak istediğinizi varsayalım Element
. Daha sonra aşağıdakilerden birini yapabilirsiniz:
iki sınıf bildirin: SomeSpecificCollection
ve Element
- kötü, çünkü "Element" ismi olası bir isim çatışmasına neden olacak kadar genel
bir ad alanı tanıtmak someSpecificCollection
ve sınıfları bildirmek someSpecificCollection::Collection
ve someSpecificCollection::Element
. İsim çatışması riski yok, ama daha ayrıntılı olabilir mi?
iki küresel sınıf ilan SomeSpecificCollection
ve SomeSpecificCollectionElement
- küçük dezavantajları vardır, ama muhtemelen sorun yok.
global sınıfı SomeSpecificCollection
ve sınıfı Element
iç içe sınıfı olarak ilan eder. Sonra:
- Öğe genel ad alanında olmadığı için hiçbir adın çakışması riskini almazsınız,
- uygulamanızda
SomeSpecificCollection
adil Element
ve başka her yerdeSomeSpecificCollection::Element
, 3 ile aynı görünen, + görünen, ancak daha açık olan
- "koleksiyonun belirli bir öğesi" değil, "belirli bir koleksiyonun öğesi" olması çok basit
- o
SomeSpecificCollection
da bir sınıftır.
Bence son varyant kesinlikle en sezgisel ve dolayısıyla en iyi tasarım.
Vurgulayayım - Daha ayrıntılı isimlerle iki küresel sınıf yapmaktan büyük bir fark yok. Bu sadece küçük bir detay, ama imho kodu daha net hale getiriyor.
Sınıf kapsamı içinde başka bir kapsamın tanıtımı
Bu özellikle typedefs veya enum'ları tanıtmak için kullanışlıdır. Buraya bir kod örneği göndereceğim:
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
};
Biri arayacak:
Product p(Product::FANCY, Product::BOX);
Ancak, kod tamamlama önerilerine bakarken Product::
genellikle listelenen tüm olası numaralandırma değerlerini (BOX, FANCY, CRATE) alır ve burada bir hata yapmak kolaydır (C ++ 0x'in güçlü yazılan numaralandırmalar bunu çözer, ama boş verin) ).
Ancak, yuvalanmış sınıfları kullanan bu numaralandırmalar için ek kapsam eklerseniz, işler şöyle görünebilir:
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
};
Sonra çağrı şöyle görünür:
Product p(Product::ProductType::FANCY, Product::ProductBoxType::BOX);
Sonra yazarak Product::ProductType::
bir IDE , yalnızca önerilen kapsamdan numaralandırmalar alınacaktır. Bu aynı zamanda hata yapma riskini de azaltır.
Tabii ki bu, küçük sınıflar için gerekli olmayabilir, ancak çok sayıda numaralandırma varsa, istemci programcıları için işleri kolaylaştırır.
Aynı şekilde, ihtiyaç duymanız halinde, bir şablonda çok sayıda typedef'i "organize edebilirsiniz". Bazen faydalı bir model.
PIMPL deyimi
PIMPL (Pointer'dan IMPLementation'a kısaltma), bir sınıfın uygulama ayrıntılarını başlıktan kaldırmak için yararlı bir deyimdir. Bu, başlığın "uygulama" kısmı her değiştiğinde sınıfın başlığına bağlı olarak sınıfların yeniden derlenmesi ihtiyacını azaltır.
Genellikle iç içe bir sınıf kullanılarak uygulanır:
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
Tam sınıf tanımının, ağır veya sadece çirkin bir üstbilgi dosyasına (WinAPI al) sahip bazı harici kitaplıklardan tanım gerektirmesi özellikle yararlıdır. PIMPL kullanıyorsanız, WinAPI'ye özgü işlevleri yalnızca içine ekleyebilir .cpp
ve asla içine dahil edemezsiniz .h
.