2014-09-14 1 views
0

파생 클래스에 고유 한 몇 가지 메서드를 활용하기 위해 기본 클래스 포인터를 파생 된 포인터로 캐스팅하고 싶습니다. 수업. 여기에 작동하는 간단한 예제의 Ideone입니다 :추가 템플릿 매개 변수를 전문으로하는 파생 포인터에 대한 특수 기본 포인터 캐스팅 (특수 대상에 추가)

template<typename A> 
class Base {}; 

template<typename A, typename B> 
class Derived : public Base<A> { 
public: 
    void doSomething() {} 
}; 

int main() { 
    Base<int>* foo = new Derived<int, double>; 
    static_cast<Derived<int, double>*>(foo)->doSomething(); 
    return 0; 
} 

을 이제 문제는, 내가 돈 내 foo는 템플릿 클래스의 멤버,

template<typename A> 
class Container 
{ 
public: 
    Base<A>* foo; 
}; 

실제로와 시간에 내가 캐스팅이다 ,

int main() { 
    Container<int> container; 
    container.foo = new Derived<int, double>; 

    // a lot of code later... 
    static_cast<Derived< /* ??? */ , double>*>(container.foo)->doSomething(); 

    return 0; 
} 

가 그럼 난 어떻게 든 A 내 기본 클래스에 무엇을 저장할 수 있다면 이것이 가능 될 줄 알았는데 '는 t는 A가 무엇인지 같은

template<typename A> 
class Base 
{ 
public: 
    static type template_type = A; // made-up syntax 
}; 

나는

static_cast<Derived<container.template_type, double>*>(container.foo)->doSomething(); 

처럼 참조 할 수 있도록하지만 this question에 따라 C++로 유형을 저장할 수 없습니다.

A을 몰라도이 캐스트를 어떻게 얻을 수 있습니까?

즉, 추가 기본 템플릿 매개 변수를 전문으로하는 파생 포인터에 특수 기본 포인터를 어떻게 캐스팅합니까? 덜 전문적인 용어로, 나는 Base 포인터와 을 택하여 Derived 포인터를 형성하는 데 필요한 다른 특수화 인을 압정하고 싶습니다.

+0

확실하게 당신은 A 형이 무엇인지 알고 있습니다. 왜냐하면 여러분이 던지려고하는 Base 타입의 객체를 갖고 있기 때문입니다. – ajclinto

+0

그게 내가 계속 생각하고있는 것인데, 이상하게 들릴지 모르겠다. 셋업에서 'A'를 알 수있는 방법이 없다. 다시 한번 살펴 보시고 이유를 보여주기 위해 조금 더 편집하십시오. –

+0

@ajclinto - 아니, 네가 옳았다. 나는 그것을 알아. 나는 똑같은 직감을 가졌지 만 그것을 전에 보지 못했다. 나는'컨테이너 '요소를 인쇄하기 위해 설계된 유틸리티 함수가 제네릭이어야한다고 생각했기 때문에'A '가 무엇인지 알 수 없다고 생각했습니다. 그러나 코드를 추적 한 후에는이 유틸리티 함수가 특정 유형의 'A'컨테이너에 대해서만 호출 될 수있는 기회를 얻게된다는 사실을 깨달았습니다. 이전에는 잘못 생각 했었지만 실제로는 A 유형을 하드 코딩하는 것이 맞습니다 그것이 인쇄 될 것입니다. 논리가 작동합니다! 이 질문을 마무리하십시오. –

답변

1

일반적으로 업 - 캐스트를 수행하는 것이 좋지 않으며 일반적으로 업 - 캐스팅의 필요성을 피하기 위해 사용할 수있는 더 나은 디자인이 있지만 실제로 필요한 경우에는 dynamic_cast을 사용할 수 있습니다 이 작업을 수행.

이 연산자는 한 유형에서 다른 유형으로 동적으로 변환하려고 시도하며 변환이 불가능한 경우 nullptr을 반환합니다. 하지만 적어도 하나의 virtual 함수를 가진 다형 타입에서만 작동한다는 것을 기억하십시오.이 경우 Base 클래스는 다형성을 가져야합니다 (기본 클래스에 대한 포인터를 보유하고 있으므로 delete을 허용하는 가상 소멸자가 필요합니다). 기본 포인터에서 작업하면 Base이 다형성 클래스가됩니다.

그러나 C++의 유형을 기억하는, 당신은 두 가지 옵션이 있습니다 :

  • 사용 typedef을 :

당신은 클래스 타입 정보를 보유하는 타입 정의를 사용할 수 있습니다 :

template< class A > 
class my_class 
{ 
public: 
    typedef A input_type; 
}; 

template< class T > 
void do_something(T const& t) 
{ 
    typename T::input_type n; 
    do_something_on_input_type(n); // possibly overloaded for different input types 
} 

이 접근 방식은 정말 빠르며 런타임에 오버 헤드가 없지만 컴파일 타임에 무언가를하고 싶을 때만 사용할 수 있습니다. 포인터의 유형이 런타임까지 결정되지 않으면이 접근법은 유용하지 않습니다.

이 실제로 클래스 유형의 정보를 저장할 수있는 사용 :

class Base { virtual std::type_info const& get_type() const = 0; }; 
class Child : public Base 
{ 
    virtual std::type_info const& get_type() const { return typeid(Child); 
    void child_specific_function() { /**/ } 
} 
class ChildOfChild : public Child 
{ 
    virtual std::type_info const& get_type() const { return typeid(ChildOfChild); } 
    // ... 
}; 

void do_something(Base* base) 
{ 
    if (base->get_type() == typeid(Child)) 
    { 
     static_cast<Child*>(base)->child_specific_function(); 
    } 
} 

이 소리는 정말 재미 있지만 정확한 유형을 알고있을 때, 그것은 단지 유용 개체이며 파생 형식에서는 작동하지 않으므로이 접근 방식은 Child에 대해 작동하지만 ChildOfChild에 대해

관련 문제