2013-04-20 1 views
0

virtual 메서드는 polymorphism의 C++ 구현의 일부입니다. RTTI ** 및 메소드 조회와 관련된 오버 헤드를 피하는 것 이외에 virtual을 생략 할 수밖에없는 이유가 있습니까?비 가상 메서드를 언제 다시 정의해야합니까?

virtual을 기본 클래스에 언제든지 추가 할 수 있다고 가정하면 virtual 메서드를 재정의하는 것이 무슨 목적으로 사용됩니까?

** 최신 CPU에서 측정 가능 여부는이 질문과 관련이 없습니다.

+0

이것이 특정 교재의 질문인지 묻습니다. 나는 단지 궁금하다! – Yakk

+0

CRTP에 대해 들어 보셨습니까? 만약 당신이 익숙하지 않다면 그것을 보아라. – Mehrdad

+0

@ Yakk - Nope, 나는 개발 중에 생각했다. – Unsigned

답변

2

글쎄, 가상이 아닌 기능을 재정의 할 이유가 거의 없습니다. 사실 똑같은 객체에서 같은 함수 호출이 사용 된 포인터/참조의 정적 유형에 따라 다르게 동작 할 수있는 것처럼 보이는 것에 대해 나는 반대 할 것을 권장합니다.

을 재정의하면 가상 구성원 함수를 사용하여 파생 형식의 동작을 특수하게 지정할 수 있습니다. 이 아닌 가상 멤버 함수가 오버로드되면 대신에 다른 동작을 제공합니다.이 동작에서는 함수/동작 중 어떤 것이 실행되는지 일반 독자에게 분명하지 않을 수 있습니다.

+0

기본, 템플릿의'void read (size_t n, void * bytes)'템플릿에서 void 읽기 (size_t n, T * instances)'- 조금 의심 스럽지만 ...? 공변 반환 형식? (부모는'Base'를 리턴하고, 자식은 부모가'Derived'를 보유하고 캐스트를 제공함을 안다.) CRTP 파생 된 구현체가 구문적인 설탕 이유 때문에 CRTP 인스턴스에서 호출되는 경우 (CRTP 클래스에서'Foo()'를 호출 할 때마다'self() -> Foo()'를 한정하지 않아도 됨) ? – Yakk

+0

@Yakk : 재정의 (override)없이 * 공분산 *을 사용할 수 없습니다.'read' 나 CRTP의 경우, 기본 함수와 파생 함수에서 같은 함수 이름을 가지고 있다면 언급 한 문제를 쳤습니다 : 포인터/참조의 정적 유형에 따라 혼동을 일으킬 수있는 다른 함수를 얻을 수 있습니다 . 더 나은/다른 이름을 선택하면 사용자가 명확하고 단순하게 만들 수 있습니다. –

+0

'struct Base {X * foo(); }; 구조체 파생 : Base {Y * foo() {return static_cast (Base :: foo();}};)은 기본적으로 정적 공분산이며 전혀 혼동하지 않습니다. – Yakk

2

한 가지 가능한 사용은 기능의 기본 버전이 정의되어 CRTP 프레임 워크를 구현하기위한 수 :

#include <iostream> 

//This could be any higher-order function. 
template<typename T> 
class CallFiveTimes { 
    protected: 
    void docalls() const { 
     for(int i(0); i != 5; ++i) static_cast<T const*>(this)->callme(); 
    } 
    //Default implementation. If a lot 
    //of different functionality were required of `T` 
    //then defaults could make `T` easier to write. 
    void callme() const { 
     std::cout << "Default implementation.\n"; 
    } 
}; 

class Client : CallFiveTimes<Client> { 
    public: 
    void useFramework() { 
     docalls(); 
    } 
    private: 
    friend struct CallFiveTimes<Client>; 
    //This redefinition will be used. 
    void callme() const { 
     std::cout << "Client implementation.\n"; 
    } 

}; 

class LazyClient : CallFiveTimes<LazyClient> { 
    public: 
    void useFramework() { 
     docalls(); 
    } 
    friend struct CallFiveTimes<LazyClient>; 
}; 

int main() { 
    Client c; 
    c.useFramework(); //prints "Client Implementation" five times 

    LazyClient lc; 
    lc.useFramework(); //prints "Default Implementation" five times 
} 

나는이 연습에서 수행 본 적이 있지만, 어떤 경우에 고려 가치가있을 수 있습니다.

관련 문제