2012-12-10 2 views
0

I라는 클래스가 'ValueChecker'다음 멤버 함수를 갖는다파생 된 유형을 기본 멤버 템플릿 함수에 전달하는 우아한 방법은 무엇입니까?

:

template<typename T> 
bool ValueChecker::checkMe(std::ostringstream &oss, T &me) { 
    std::cout << "Default checkMe() for " << typeid(me).name() << std::endl; 
    return true; 
} 

ValueChecker 파생 클래스의 값에 간단한 확인을 수행하도록 구성되는, 클래스. checkMe()는 결국 다른 파생 클래스에 대한 전문 얻을 것이다 :

class Airplane : public ValueChecker { 
    friend class ValueChecker; 
    [...] 
} 


template<> 
bool ValueChecker::checkMe<Airplane>(std::ostringstream &oss, Airplane &me) { 
    ...  
    /* Actually, this code is generated from a simple file which translates 
    * a simple language into C++ code. So that a non-developer can write 
    * the simple checks. 
    * 
    * ValueChecker itself has utility functions that may be called in the 
    * template specialization which are shared across all types. 
    */ 

} 

이 작동하지만, 당신이 호출 볼 때 단지 작은 문제가, checkMe의 선언으로있다 :

int main() { 
    Airplane plane; 
    std::ostringstream oss; 

    if(plane.checkMe(oss, plane)) { 
    cout << "Values are bogus! " << oss.str() << endl; 

    return 0; 
} 

I plane.checkMe (oss, plane)를 호출하십시오. 그러나 비행기를 점검하지 않고 다른 비행기를 통과 할 수도 있습니다. 게다가, 호출은 중복인가? 컴파일러는 이론적으로 비행기의 유형에 따라 호출 할 템플릿 함수를 알아야합니다. 그것을 인수로 전달할 필요가 없어야합니까? 어쨌든 마지막 인수를 제거하지 않는 것이 좋습니다. 따라서 이와 같은 전화는 좋을 것입니다 :

if(plane.checkMe(oss)) { ... } // Calls the right template specialization. 

나는 그걸 작동시킬 수 없습니다. C++ 전문가가 나를 도와 줄 수 있습니까? 감사.

+0

이 포인터를 typeid에 전달할 수 없습니까? –

+0

CRTP (http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern) – Chubsdad

+0

을 평가하셨습니까? 처음에는 다소 이상한 디자인으로 보입니다. '비행기'가 'ValueChecker'에서 파생 된 이유는 무엇입니까? 'checkMe()'가'T '형의 인수를 취하는 이유는 무엇입니까? (질문에서 판단 할 때)'this' 만 체크해야하는 이유는 무엇입니까? – Angew

답변

3

순수 가상 메서드로 구현할 수 있습니다.

class ValueChecker 
{ 
public: 
    virtual bool checkMe(std::ostringstream& oss) = 0; 
}; 

class Airplane : public ValueChecker 
{ 
public: 
    virtual bool checkMe(std::ostringstream& oss); 
}; 

그런 식으로 plane.checkMe(oss)으로 전화하면 checkMe- 비행기의 메소드가 호출됩니다.

3

주어진 코드의 경우 실제로 template 또는 friend을 사용할 필요는 없습니다. 대신 상속을 사용하고 checkMe() 메서드를 protectedvirtual 메서드로 만듭니다. 그런 다음 파생 클래스에서 checkMe() 메서드를 재정의합니다. 기본 구현이 필요하지 않은 경우 순수 가상으로 만들 수도 있습니다. 다음은 예제를 기반으로 한 간단한 코드입니다. (this 포인터의 사용을합니다.) 논리 이외에, 파생 클래스에 특정한 하나 이상의 파생 클래스에서 사용하려면 몇 가지 "일반적인"논리있을 때

class ValueChecker { 
protected: 
    virtual bool checkMe() { 
     std::cout << "Default checkMe() for " << typeid(this).name() << std::endl; 
     return true; 
    } 
}; 

class Airplane : public ValueChecker { 
public:  
    virtual bool checkMe() { 
     std::cout << "Airplane checkMe() for " << typeid(this).name() << std::endl; 
     return true; 
    } 
}; 

int main() { 
    Airplane plane; 
    plane.checkMe(); 
} 

당신은 기본 구현을 필요 그 자체. 이 경우 범위 분석 연산자를 사용하여 기본 클래스의 논리에 액세스하십시오.

bool Airplane::checkMe() { 
     std::cout << "Airplane checkMe() for " << typeid(this).name() << std::endl; 

     // use the "common" logic from the base class (if required) 
     ValueChecker::checkMe(); 

     return true; 
    } 
+0

@Bitdiot 귀하의 질의가 처리 된 경우, 답변을 upvote하고 답변을 수락 해 주시겠습니까? (나는 내가 좋아할 것이다 :)) –

0

자주 수행하는 일반적인 트릭이있다 : 당신을 위해 트릭을 할 수 http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern .

+0

CRTP는 여기에 실제로 필요하지 않습니다. 더 쉬운 해결책이 있습니다. 비록 제가 질문에 구현 된 방식에 동의하지만, 그것은 CRTP처럼 보입니다. –