1

저는 매트릭스 클래스를 작성하고 있습니다. 다음 정의를 살펴보십시오.파생 된 템플릿은 멤버 함수의 반환 유형을 재정의합니다. C++

template <typename T, unsigned int dimension_x, unsigned int dimension_y> 
class generic_matrix 
{ 
    ... 
    generic_matrix<T, dimension_x - 1, dimension_y - 1> 
    minor(unsigned int x, unsigned int y) const 
    { ... } 
    ... 
} 

template <typename T, unsigned int dimension> 
class generic_square_matrix : public generic_matrix<T, dimension, dimension> 
{ 
    ... 
    generic_square_matrix(const generic_matrix<T, dimension, dimension>& other) 
    { ... } 
    ... 
    void foo(); 
} 

generic_square_matrix 클래스는 행렬 곱셈과 같은 추가 기능을 제공합니다. 는 이렇게하면 아무 문제가 없다 :

generic_square_matrix<T, 4> m = generic_matrix<T, 4, 4>(); 

타입이 때문에 생성자에, generic_square_matrix되지 않더라도, M 어떤 정방 행렬을 할당 할 수 있습니다. 이는 데이터가 하위 항목간에 변경되지 않고 지원되는 기능 만 변경 될 수 있기 때문에 가능합니다. 가능한 경우 :

generic_square_matrix<T, 4> m = generic_square_matrix<T, 5>().minor(1,1); 

동일한 변환이 여기에 적용됩니다. 하지만 지금은 문제가 온다 :

generic_square_matrix<T, 4>().minor(1,1).foo(); //problem, foo is not in generic_matrix<T, 3, 3> 

내가 generic_square_matrix :: generic_matrix 대신 generic_square_matrix를 반환 사소한 싶습니다이 해결합니다. 이렇게하는 유일한 방법은 템플릿 전문화를 사용하는 것입니다. 그러나 전문화는 기본적으로 개별 클래스처럼 취급되므로 모든 기능을 재정의해야합니다. 파생 된 클래스를 사용하는 것처럼 비 전문 클래스의 함수를 호출 할 수 없기 때문에 전체 함수를 복사해야합니다. 이것은 매우 훌륭한 일반 프로그래밍 솔루션이 아니며 많은 노력을 필요로합니다.

C++에는 거의 내 문제에 대한 해결책이 있습니다. 파생 클래스의 가상 함수는 기본 클래스가 반환하는 클래스에서 파생 된 경우 기본 클래스가 반환하는 다른 클래스에 대한 포인터 또는 참조를 반환 할 수 있습니다. . generic_square_matrix 은 generic_matrix에서 파생 된이지만 함수는 포인터도 참조도 반환하지 않으므로 여기서는 적용되지 않습니다.

이 문제에 대한 해결책이있을 수 있습니다 (아마도 완전히 다른 구조가 포함될 수 있습니다. 필자의 유일한 요구 사항은 치수가 템플릿 매개 변수이며 사각형 매트릭스가 추가 기능을 가질 수 있다는 것입니다). 사전에

감사합니다,

루드

답변

4

당신은 그냥 가상 않고 파생 클래스의 기능을 구현할 수있다. 이것은 기본 클래스 구현을 "숨기"때문에 멤버 함수를 숨기는 일반적인 혐오감에도 불구하고 사용하기에 바람직 할 수 있습니다.

더 나은 방법은 다른 이름을 사용하는 것일 수도 있지만 인터페이스의 "순도"를 떨어 뜨릴 수 있습니다.

마지막으로 minor()를 멤버 함수 대신 자유 함수로 구현할 수 있습니까? 그런 다음 적절하게 오버로드를 제공 할 수 있으며 컴파일 타임에 올바른 함수가 호출됩니다. 이것은 내가 열어 둔 메소드 숨기기에 가장 가깝지만 "더 좋은 습관"으로 받아 들여질 수 있을지는 의심 스럽다.

+0

대단히 감사드립니다. 멋지고 단순하며 우아한 솔루션입니다 (적어도이 경우). 서로 다른 클래스에서 다른 멤버를 호출해야하기 때문에 서로 다른 이름을 사용하면 좋지 않습니다. 기본적으로 동일한 작업을 수행합니다. minor() _could_는 무료 함수로 구현 될 수 있지만 멋진 OOP 솔루션은 아닙니다. 단, 부 번호는 행렬의 속성입니다. 함수 숨기기가 "우수 사례"가 아닐 수도 있지만,이 경우에는 함수 구현 자체가 변경되지 않기 때문에 생각합니다. (그리고 더 좋은 행렬 클래스를 허용합니다.) – Ruud

+2

@Ruud : 자유 함수가 객체의 인터페이스에 속한다고 주장 할 수 있습니다. [ "비회원 기능이 캡슐화를 향상시키는 방법"(http://www.drdobbs.com/184401197). –

+2

@Ruud : OO는 모든 문제에 대한 해결책이 아니라 끝을내는 수단입니다. C++은 __multi-paradigm__ 언어이며 패러다임이 섞여있는 곳에서 가장 밝게 빛납니다. STL은 그 좋은 예입니다. 얼마나 강력한 지 알아보십시오. 상속이 전혀없고 대부분의 알고리즘은 컨테이너 멤버가 아닌 자유 함수입니다. – sbi

0

템플릿 전문화 작업이 가능합니다. 당신이하는 일은 공유 된 코드를 기본 클래스에 넣은 다음 두 클래스 모두로부터 상속받는 것입니다. 기본에 소멸자를 보호하여 아무도 기본에 캐스팅하지 않고 삭제하려고 시도하지 않도록하십시오.그래서 같은

뭔가 :

namespace detail_ 
{ 
    template < typename T > 
    struct my_templates_common_functionality 
    { 
    void f1() {} 
    void f2() {} 
    protected: 
    ~my_templates_common_functionality() {} 
    }; 
} 

template < typename T > 
struct my_template : detail_::my_templates_common_functionality<T> 
{ 
    int f3() { return 5 } 
}; 

template < > 
struct my_template<double> : detail_::my_templates_common_functionality<double> 
{ 
    char* f3() { return nullptr; } 
}; 

다른 방법이 있습니다,하지만 가장 쉬운 중 하나입니다.

template<typename T, unsigned int X, unsigned int Y> 
generic_matrix<T, X-1, Y-1> 
minor(const generic_matrix<T, X, Y>& m, unsigned int x, unsigned int y); 

다음 당신은 당신이 원하는만큼 대체 버전을 추가 할 수 있습니다 .. : 당신은 단순히 minor() 무료로 기능을 할 수 있다면 디자인을 복잡 필요가 없습니다

3

.

+1

일반적으로 무료 기능이 제공됩니다.사람들이 객체 지향 설계 (특히 Java/C#에는 무료 기능이 없기 때문에)에 대해 많은 잘못된 조언을 읽은 것입니다. 그리고 나서 그들은 일반적인 프로그래밍을 발견하고 그들의 (나쁜) OOP 반사는 적합하지 않습니다./ –

+1

@Matthieu : 나는 그 코멘트에 +10을 줄 수 있었으면 좋겠습니다. – sbi

1

이러한 유형을 다형 적으로 사용하지 않는 경우 파생 클래스 객체를 반환하도록 파생 클래스의 기본 클래스 메소드를 가상이 아닌 메소드로 대체 할 수 있습니다. 일반적으로 원하지 않는 기본 클래스 버전을 숨길 수 있지만 귀하의 경우에는 그렇다고 볼 수 있습니다.

또는 다른 유형의 행렬에 대한 오버로드가있는 경우 필요에 따라 이러한 멤버 함수를 자유 함수 템플릿으로 만듭니다. 템플릿 설정이 자동으로 처리 될 수도 있지만

관련 문제