2013-10-31 2 views
0

다음은 내가 수행하고자하는 작업입니다.C++ 11 템플릿 기반이 아닌 기본 클래스의 순수 가상 템플릿 형식 return

다양한 유형의 링크 된 목록을 만들려고합니다. 이것을 달성하기 위해, 나는 다형성이 좋은 방법이 될 것이라고 생각했습니다.

저는 AttributeBase와 Attribute의 두 클래스가 있습니다. AttributeBase는 AttributeSet에 의해 사용되며, AttributeBase *의 속성으로 연결된 <T>의 연결 목록의 시작과 끝 지점을 저장하고 목록에서 수정을 수행합니다. AttributeBase는 일반 포인터를 만들기위한 목적으로 만 디자인 된 속성 <T>의 기본 클래스입니다. 속성 <T>은 물론 실제 값이 저장된 AttributeBase의 특정 유형입니다.

: 각 속성 <T>의 주요 데이터는 지금까지 내가 (간체) 한 상속 된 문자열 (속성의 이름, 또는 '키'만약에 당신)와

그래서 T 형식의 값을,이다

class AttributeBase 
{ 
    public: 
    AttributeBase() = delete; 
    AttributeBase* GetNext() { return next; }; 
    AttributeBase* GetPrev() { return prev; }; 
    std::string GetName() { return name; }; 
    //Sometimes I need to get/set the value stored in a derived class 
    //But, how would I define the function here since the return 
    //type is of type T as defined in Attribute? 
    virtual ???? GetValue = 0; 
    virtual void SetValue(????) = 0; 

    friend class AttributeSet; 
    private: 
    AttributeBase* next = nullptr; 
    AttributeBase* prev = nullptr; 
    std::string name; 
}; 

template <class T> 
class Attribute : public AttributeBase 
{ 
    public: 
    Attribute(std::string _name, T _value){ name = _name; value = _value }; 
    T GetValue(){ return value; }; 
    void Setvalue(T){ value = T; }; 
    private: 
    T value; 
}; 

class AttributeSet 
{ 
    public: 
    template <class T> 
    void Add(std::string,T); //Add an Attribute<T>(std::string,T) to the list 
    void Delete(std::string); 
    bool Contains(std::string _name); //Scan the list to determine if an 
             //attribute with name of _name exists 
    template <class T> 
    T Get(std::string); //Scan the list for 'name' and return 
         //AttributeBase*->GetValue() 
    private: 
    AttributeBase* start = nullptr; 
    AttributeBase* end = nullptr; 
} 

AttributeBase를 일반화하고 애트리뷰트 세트에 강하게 입력 된 시작 및 끝 포인터를 방지하기 위해 템플릿을 사용하지 않으려 고 시도한 이래로 문제가 발생합니다. 어떻게 가상 함수 BaseAttribute :: GetValue()에 대해 아직 지정되지 않은 반환 유형을 지정합니까? 먼저 auto을 사용하여 컴파일 오류가 발생했습니다.

AttributeBase의 인스턴스가 실제로 생성되지 않고 (그리고 기본 생성자가 삭제 된) GetValue를 생략하고 파생 클래스에서 정의 할 수 있다고 생각했습니다. 그러나 * AttributeBase-> GetValue()를 시도하면 GetValue()가 AttributeBase에만 정의되어 있지 않으므로 오류가 발생합니다. 하위 클래스 만 정의됩니다. AttributeBase를 직접 생성 할 수 없기 때문에 포인터가 파생 클래스 (유일하게 파생 된 유형)를 가리켜 야한다는 것을 컴파일러가 알고 있다고 생각할 것입니다.

그래서 GetValue()를 사용하려면 AttributeBase *를 Attribute *로 형 변환 할 수 있도록 이전 값의 유형을 미리 알아야합니다. 이것은 AttributeBase 자체가 템플리트 화되고 값 T 유형을 포함하는 경우 사소한 것입니다. 그런 다음 AttributeBase * -> type에 액세스하여 캐스팅해야하는 포인터의 유형을 결정할 수 있습니다. 그러나, 내가 말했듯이, AttributeBase 템플릿은 객체의 의도 된 사용을 파괴합니다.

아마도 나는 완전히 잘못된 방식으로 (아직 또 다시)이 문제에 대해 이야기 할 것입니다. 그러나이 시점에서 나는 아이디어에 매달렸다. 어떤 도움을 주시면 감사하겠습니다!

+0

'AttributeBase :: GetValue' 또는'AttributeBase :: SetValue'를 사용하는 코드 예제를 줄 수 있습니까? – aschepler

답변

1

진정한 해결책은 존재하지 않습니다. 기본 클래스 가상 함수의 모든 재정의가 동일한 반환 유형을 가져야하므로 기본 클래스에서 임의의 형식을 가져올 수 없습니다.

두 가지 옵션이 있습니다.

먼저 공통 기본 유형에서 파생 된 객체를 목록에 보유하도록 미리 결정할 수 있습니다. 이것은 당신이 당신의 목록에 넣을 수있는 것을 심각하게 제한 할 것입니다.

둘째, 목록에있는 개체로 실제로 수행 할 작업에 따라 새 Boost.TypeErasure 라이브러리를 볼 수 있습니다. 목록으로해야하는 모든 것이 출력되거나 소량의 작업으로 이루어지면이 작업을 수행하는 데 도움이 될 수 있습니다.

+0

유형이 공변 (covariant) 인 경우 다른 리턴 유형으로 대체 할 수 있음을 지적합니다. 이 경우에는 실제로 적용 할 수 없지만. –

+0

나는 Boost :: Asio를 이미 내 서버 코드에 사용하고있다. (너무 간단하다!) 그래서 Boost의 또 다른 비트가 너무 많이 아프지 않을 것이라고 생각한다. 나는 그것을보고 곧 희망을 갖고 다시보고 할 것이다. 나는 Boost에 익숙하지 않다는 것을 알아야한다. 그래서 조금 시간이 걸릴 것이다;) –

+0

@ FrançoisMoisan 맞아,이 경우에는 표준 목록을 내 목록에 저장하려고한다. –

0

GetValueSetValue의 서명은 템플릿에 의존하므로 서명해야합니다.그러나 그들은 클래스 템플릿을 요구하지 않고 템플릿 멤버가 될 수 있습니다.

하나의 잡았다 : 잘못된 유형을 사용하는 경우 이러한 기능은 모두 예외를 throw합니다. SetValue은 템플릿 인수를 자동으로 추론 할 수 있으며 잘못 입력 할 수도 있습니다. 예를 들어 aAttributeBase& 참조 인 경우 실제로 Attribute<long int> 인 경우 a.SetValue(1)a.SetValue<int>(1)과 같아집니다. 올바른 표현식은 a.SetValue<long int>(1) (또는 a.SetValue(1L)이지만 명시 적 템플릿 인수를 선호합니다).

+0

그건 꽤 똑똑 해요. 나는 그것에 대해 생각하지 않았습니다. 만약 그들이 템플리트를 쓰고 있다면 꼭 가상 일 필요는 없다 ...하지만 내가 이렇게하면, AttributeSet.Set ("thename", 25)과 같은 것을 할 수 없을 것이다. 사용 된 유형을 나타내는 AttributeBase에 값을 저장하는 것과 같습니다. 그런 다음 모호한 (int, long, short 등) 값을 설정하려고 할 때마다 전환해야합니다. 나는 방금 아래에서 추천 한 Boost로 끝냈다. (그래서 나는 그것을 최고로 표시 할 것이다.) 그러나 나는 너의 길을 시도 할 것이고 그것이 어떻게되는지 볼 것이다. = D –

+0

나는 너의 길에서 그것을 잘 풀 수 있었다. D 참고 사항 중 하나는, 포인터를 사용했기 때문에 (이것은 결국 링크 된 목록 임) dynamic_cast를 static_cast로 변경해야한다는 것입니다. 오류가 발생했습니다 : 오류 : '클래스 속성 \ * const'(소스 유형이 다형성이 아님)을 입력하기 위해 dynamic_cast '\ * (AttributeBase (소스 유형이 다형성이 아님) –

+0

"소스 유형이 다형성이 아님"오류를 수정하려면, 다음과 같은 소멸자를 작성하면됩니다 (예 : \ *) this '('AttributeBase '유형의)'class Attribute & ' 'AttributeBase' 가상 (어쨌든 좋은 생각입니다). – aschepler

관련 문제