중첩 클래스는 일반 클래스와 비슷하지만
- (클래스 정의 내부의 모든 정의와 마찬가지로) 추가 액세스 제한이 있습니다.
- 그들은 주어진 네임 스페이스를 오염시키지 않는 글로벌 네임 스페이스를 예. 클래스 B가 클래스 A에 너무 깊게 연결되어 있다고 생각하지만 A와 B의 객체가 반드시 관련이있는 것은 아니라면 A 클래스 범위 지정을 통해서만 클래스 B에 액세스 할 수 있기를 원할 수 있습니다 (A라고 함). ::수업).
몇 가지 예 :
클래스를 공개적으로 중첩하여 관련 클래스의 범위에 배치
class의 SomeSpecificCollection
객체를 집계 하는 클래스를 원한다고 가정하십시오 Element
. 그러면 다음 중 하나를 수행 할 수 있습니다.
두 개의 클래스를 선언합니다 : SomeSpecificCollection
그리고 Element
- "Element"라는 이름이 이름 충돌을 일으킬 정도로 일반적이기 때문에 나쁩니다.
네임 스페이스를 소개 someSpecificCollection
하고 클래스를 선언 someSpecificCollection::Collection
하고 someSpecificCollection::Element
. 이름 충돌의 위험은 없지만 더 자세한 정보를 얻을 수 있습니까?
이 개 글로벌 클래스 선언 SomeSpecificCollection
과 SomeSpecificCollectionElement
- 사소한 단점이 있지만, 아마 OK이다.
전역 클래스 SomeSpecificCollection
와 클래스 Element
를 중첩 클래스로 선언하십시오 . 그때:
- Element가 전역 네임 스페이스에 없기 때문에 이름 충돌의 위험이 없습니다.
SomeSpecificCollection
당신 을 구현할 때 just Element
, 그리고 다른 곳 SomeSpecificCollection::Element
은-3과 같지만 +와 동일하지만 더 명확합니다.
- "컬렉션의 특정 요소"가 아니라 "특정 컬렉션의 요소"라는 것이 단순 해집니다.
- 그 볼
SomeSpecificCollection
도 클래스입니다.
제 생각에는 마지막 변형이 가장 직관적이며 따라서 최고의 디자인입니다.
스트레스를 드리겠습니다-더 자세한 이름을 가진 두 개의 글로벌 클래스를 만드는 것과 큰 차이는 없습니다. 아주 작은 세부 사항이지만 코드를 더 명확하게 만듭니다.
클래스 범위 내에서 다른 범위 소개
이것은 typedef 또는 enum을 도입 할 때 특히 유용합니다. 여기에 코드 예제를 게시하겠습니다.
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
};
그런 다음 다음을 호출합니다.
Product p(Product::FANCY, Product::BOX);
그러나에 대한 코드 완성 제안을 살펴보면 Product::
가능한 모든 열거 형 값 (BOX, FANCY, CRATE)이 나열되어 있고 여기에서 실수하기 쉽습니다 (C ++ 0x의 강력한 형식의 열거 형은 해결하지만 결코 신경 쓰지 않습니다) ).
그러나 중첩 클래스를 사용하여 열거 형에 대한 추가 범위를 도입하면 다음과 같이 보일 수 있습니다.
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
};
그런 다음 호출은 다음과 같습니다.
Product p(Product::ProductType::FANCY, Product::ProductBoxType::BOX);
그런 다음 Product::ProductType::
IDE 에 입력 하면 원하는 범위에서 열거 형을 얻을 수 있습니다. 또한 실수 할 위험이 줄어 듭니다.
물론 이것은 작은 클래스에는 필요하지 않지만 열거 형이 많으면 클라이언트 프로그래머가 더 쉽게 만들 수 있습니다.
같은 방법으로, 필요한 경우 템플릿에 많은 타입 정의를 "구성"할 수 있습니다. 때로는 유용한 패턴입니다.
PIMPL 관용구
PIMPL (Pointer to IMPLementation의 줄임말)은 헤더에서 클래스의 구현 세부 사항을 제거하는 데 유용한 관용구입니다. 이렇게하면 헤더의 "구현"부분이 변경 될 때마다 클래스 헤더에 따라 클래스를 다시 컴파일 할 필요가 줄어 듭니다.
일반적으로 중첩 클래스를 사용하여 구현됩니다.
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
이것은 전체 클래스 정의가 무겁거나 못생긴 헤더 파일 (WinAPI 사용)이있는 일부 외부 라이브러리의 유형 정의가 필요한 경우에 특히 유용합니다. PIMPL을 사용하는 경우 모든 WinAPI 관련 기능 만에 .cpp
포함시킬 수 있으며에 포함시킬 수 없습니다 .h
.