2010-02-11 3 views
1

BCA에서 파생됩니다. A에서 파생 된 클래스의 두 인스턴스가 같은 클래스의 인스턴스인지 여부, 즉 과 A* barB 인스턴스를 가리키는 지 RTTI를 사용하지 않고 테스트 할 수 있기를 원합니다. 나의 현재 솔루션은이 같은 것입니다 :이 방법을 사용하면RTTI가없는 유형 평등에 대한 테스트

class A { 
protected: 

    typedef uintptr_t Code; 
    virtual Code code() const = 0; 

}; // class A 


class B : public A { 
protected: 

    virtual Code code() const { return Code(&identity); } 

private: 

    static int identity; 

}; // class B 


class C : public A { 
protected: 

    virtual Code code() const { return Code(&identity); } 

private: 

    static int identity; 

}; // class C 

, operator== 단순히 first.code() == second.code()을 테스트 할 수 있습니다. 파생 클래스에서 리터럴 identity을 제거하고 코드가 A에 의해 자동으로 검색되도록하고 싶습니다. 따라서 모든 파생 클래스가이 관용구를 반복하지 않아야합니다. 다시 말하지만, RTTI를 사용하지 않는 것이 좋습니다. 이 일을 할 수있는 방법이 있습니까?

참고 : 내가 최근 질문을 본 [1][2],이 중복되지 않습니다있다. 해당 포스터는 내용을 파생 클래스로 테스트하려고합니다. 난 단지 신분을으로 테스트하고 싶다.

+3

RTTI를 사용하지 않으면 다시 발명해야 할 운명입니다. 불완전하게. –

+0

호기심에서 벗어남 : 왜 RTTI를 사용하는 대신이 방법을 사용 하시겠습니까? –

+0

@nobugz : 나는 모든 것을 다시 발명하지는 않는다. 더 큰 기본 제공 기능에서 사용할 기능 하나만 에뮬레이트하고 있습니다. @Laurence :이 프로젝트는 어디에서나 실행할 수 있어야합니다.두 개의 정수를 비교하는 것 이상의 공간 오버 헤드와 런타임 오버 헤드를 원하지 않습니다. –

답변

3

바퀴를 다시 만들기보다는 RTTI를 사용해야합니다.

RTTI를 사용하지 않으려는 경우 CRTP와 함수 로컬 정적 변수를 사용하여 모든 파생 클래스에 함수를 작성하지 않아도됩니다. http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern#Polymorphic_copy_construction

또 다른 대안은 (this 포인터를 arithmetics를 통해)의 vtable 포인터를 읽고 있지만, 휴대용되지 않도록 즉, 컴파일러와 플랫폼 모두에 달려 : 나는 위키 백과에 대한 쓴이 예제 코드에서 적응.

+0

CRTP를 사용하라는 제안은 파생 클래스에서 중복을 제거하기 위해 완벽하게 작동했습니다. 고맙습니다! 이제는 공간을 차지하지 못하게하는 방법을 고민하고 있습니다. –

+0

함수 자체 (프로그램 코드)에는 정적 변수보다 훨씬 많은 공간이 필요합니다. – Tronic

0

id을 생성자 매개 변수로 사용하고 기본 클래스 자체에 identity() 함수를 구현하도록 기본 클래스를 만들 수 있습니다. 그런 다음 파생 클래스에서 코드를 반복 할 필요가 없습니다. 파생 클래스의 생성자에서, 당신은 derived::derived(): base(0) 예제 코드처럼 뭔가를 할 수 있습니다

class A 
{ 
public: 
    A(int n) : m_id(n) 
    { 
    } 
    virtual ~A(){} 

    virtual int id() const 
    { 
     return m_id; 
    } 

private: 
    int m_id; 
}; 

class B : public A 
{ 
public: 
    B() : A(0) 
    { 
    } 
}; 
+1

좋은 생각이지만, 파생 된 모든 클래스가 추가 작업을 수행하고 충돌의 가능성을 제시해야합니다. 또한 이상적으로 ID에는 저장이 필요하지 않습니다. –

+0

Naveen은 1+ 이상이라고 생각합니다. – Ashish

+1

태그를 클래스와 연결할 필요가있을 때마다 type 태그를 사용하여 모든 인스턴스에 태그를 지정하기 때문에 이것이 좋지 않습니다. –

-1

당신이 당신의 코드로 매크로 __FILE__ __LINE__를 모두 사용할 수 있습니다
이것은 당신이 int로이 값을 매핑 할 수 있습니다
충돌 문제를 방지합니다

+1

암시 적 템플릿 인스턴스화는 동일한 '__FILE__'및 '__LINE__'을 (를) 공유하지만 다른 클래스가되므로 불완전합니다. 그래도 흥미로운 해킹. –

+0

'__FILE__ + __LINE__' 또는 유사해야하고, 각 파생 클래스에 대해 한 번 표시해야합니다. 이는 피하려고하는 것입니다. 또한 저장소를 사용하며, 단순히 int보다 더 많은 것을 사용합니다. –

2

귀하의 아이디어는 올바른 방향입니다.

class TypeTagged { 
public: 
    virtual Code code() const = 0; 
} 

template <class T> 
class TypeTaggedImpl: public virtual TypeTagged { 
public: 
    virtual Code code() const { return Code(&id); } 
private: 
    static int id; 
} 

그런 다음 클라이언트 클래스는 단지 필요

은 다음과 같이 선언 할 : TypeTagged

class A: public TypeTaggedImpl<A> { ... } 

class B: public A, public TypeTaggedImpl<B> { ... } 

서로 다른 인스턴스화는 종류가 다른 id 필드를 가지고 있다는 것을 의미 어쩌면 당신은 템플릿 일부 상용구를 제거 할 수 있습니다 그러므로 다른 ID들; 가상 기본 유형은 가장 많이 파생 된 유형의 code이 반환됨을 의미합니다.

+0

이것은 Tronic의 답변과 동일하지만 예제를 제공하기 위해 +1합니다. –

관련 문제