2011-10-09 4 views
3

코드에는 몇 가지 특수 클래스가 있으며 일반 클래스가 있습니다. 나는 특별한 수업이 다른 치료를 받아야하기 때문에 그들을 차별화시키고 싶다.여분의 상속은 개체 구조 또는 인스턴스화에 어떤 차이가 있습니까?

struct _special {}; // empty class 
class A : public _special { // A becomes special 
... 
}; 
class B { // 'B' remains normal 
... 
}; 
class D : public A { // 'D' becomes special due to 'A' 
... 
}; 

때마다를 모든 이러한 특수 클래스는 (다른 클래스의없는 아이)

struct으로 그들에게 상속를 삽입하여 내가 소스 코드에서 특별한 class ES를 토큰 화하고 있음을 달성하기 기지 필요하다면, 나는 is_base_of<Base,Derived>을 사용하여 분리 된 특수 및 정규 수업을 찾을 수 있습니다. 대체 방법은 특별한 클래스 내부 typedef를 사용했을 것이다 :

class A { 
    public: typedef something _special; 
}; 

문제는 A의 아이가 여러 클래스에서 상속하는 경우 다음 typedef의 모호한있을 것입니다.

질문 : 빈 class _special와 상속처럼 같은 인터페이스를 추가로 의지가 그것을 어떤 방법으로 현재 코드를 상처 (예를 들어, 객체 구조, 컴파일 오류 등)? 당신이 또는 객체 구조 (관리가 정교?), 상처를하지만 전혀 컴파일러 오류, 인스턴스/생성자가 없을 것으로 무엇을 의미하는지

답변

0

확실하지 _special가 기본이 있기 때문에 변경되지 않습니다 _special에서 파생 분류 컴파일러는 빈 기본 클래스 최적화를 적용 할 수 있습니다.

즉, 클래스에 태그를 지정하기 위해 typedef를 사용하는 옵션이 더 좋고 명확하며 확장 가능한 솔루션 일 수 있습니다. 그리고 A의 자식이 _special에서 상속받을 수있는 여러 개의 다른 클래스를 상속하는 것만 큼 모호합니다.

3

대부분의 경우 괜찮은 컴파일러가 간단한 경우 EBOB (Empty Base Optimization)를 구현하지는 않습니다. 즉, 빈베이스에서 상속하여 개체 크기가 커지지 않습니다. 그러나 클래스가 하나 이상의 방법으로 빈 기지를 상속 할 때 같은 유형의 서로 다른 빈 기지에 대해 서로 다른 주소를 가질 필요가 있기 때문에 최적화가 불가능할 수 있습니다. 이를 방지하기 위해 일반적으로 빈 기본 클래스를 파생 클래스를 인수로 취하는 템플릿으로 만들지 만 is_base_of을 사용할 수 없게 만듭니다.

개인적으로, 나는이 분류를 외부 적으로 구현할 것입니다. 템플릿 특수화는 간접적으로 특수 클래스에서 파생 된 클래스의 원하는 결과를 얻지 못합니다.

std::false_type is_special(...); 
std::true_type is_special(A const*); 

을 그리고 decltype(is_special(static_cast<T*>(0)))is_base_of<T, _special> 교체 : 당신이 그렇게 내가 할 것 C++ (11)를 사용하는 것 같습니다. C에서 서로 다른 크기의 분류 함수 반환 유형을 가짐으로써, 동일한 것을 sizeof 트릭 달성 될 수 03 ++

typedef char no_type; 
struct yes_type { no_type _[2]; }; 

no_type is_special(...); 
yes_type is_special(A const*); 

그리고 sizeof(is_special(static_cast<T*>(0))) == sizeof(yes_type)으로 is_base_of<T, _special> 대체. 헬퍼 클래스 템플릿 내에서 분류 검사를 래핑 할 수 있습니다.

+0

좋은 답변이지만 C++ 11을 사용하고 있지 않습니다. – iammilind

+0

@ iammilind : 여전히 형식 특성을 사용할 수 있습니다. –

+0

@ iammilind : C++ 03 솔루션도 포함되었습니다. –

3

메모리에있는 객체의 레이아웃은 C++ 표준에서 부분적으로 만 지정되지만 대부분의 컴파일러에서 사용하는 특정 규칙이 있습니다.빈 타입은 약간의 메모리를 차지합니다 (그래서 포인터 식별자를 줄 메모리 주소를 가지게됩니다). 이 여분의 메모리는 일반적으로 단지 4 바이트이며, 대부분의 경우 걱정할 필요가 없습니다. 다른 한편으로는 빈 타입으로부터 상속 받았다면 오브젝트의 나머지 부분이 공간을 차지할 것이기 때문에 오브젝트의 크기를 늘려서는 안되기 때문에 어쨌든 주소를 가질 것입니다.

단일 상속 개체를 사용하는 경우 첫 번째 기본 클래스처럼 레이아웃 된 메모리의 첫 번째 비트가 배치되고 체인은 나중에 체인의 멤버를 보유 할 메모리가 배치됩니다. 가상 기능이 있다면 처음에는 가상 포인터를위한 장소도있을 것입니다. 하나의 유형을 다른 유형에서 파생하는 경우 일반적으로 "3 가지 규칙"(가상 소멸자, 사본 생성자 및 사본 할당 연산자)을 따르기를 원할 것입니다. 그래서 가상 포인터를 가지게 될 것입니다, 다시 이것은 아마도 4 바이트 일 것입니다, 큰 문제는 아닙니다.

다중 상속에 도달하면 개체가 구조적으로 매우 복잡해집니다. 함수는 자신이 찾고있는 멤버를 찾을 수 있도록 다양한 부분에 대한 다양한 포인터를 갖습니다.

그렇다면 이것을 모델링하기 위해 상속을 사용할지 여부를 고려하십시오. 아마도 객체에 bool 멤버 변수를주는 것이 좋습니다.

관련 문제