2011-07-02 4 views
2

나는 컴파일러가 vtable의 크기를 정확하게 결정할 수 없기 때문에 이것이 합법적이지 않다는 것을 알고있다. 나는 대안을 찾고있다.내 목표를 달성하기 위해 템플릿 가상 함수를 우회하는 방법은 무엇입니까?

기본적으로 파생 클래스 집합에 대한 인터페이스를 정의하는 추상 기본 클래스가 있습니다. 이 인터페이스를 통해 노출되는 일부 함수의 리턴 값은 입력 매개 변수 sKeyName에 의해 결정됩니다. 내 의도 된 코드는 아래에 게시됩니다.

class DataAccess 
{ 
    public: 
     template <class T> 
     virtual const Array2D<T>* GetData(std::string sKeyName) const = 0; 

     template <class T> 
     virtual Array2D<T>* GetData(std::string sKeyName) = 0; 
}; 

누군가이 기능을 사용하기위한 해결 방법을 제공 할 수 있습니까? 어떤 도움을 주셔서 감사합니다. 미리 감사드립니다.

+1

Seams는 "묻지 마십시오."설계 원리를 깨고 있습니다. 정확히 당신이 보관하려고하는 것은 무엇입니까? –

답변

0

GetData에서 반환 할 수있는 모든 다른 형식을 기본 클래스에서 상속 받고 해당 클래스에 대한 포인터를 반환합니다. 예 :이 귀하의 질문에 대한 대답,하지만 당신은 CRTP에 좀 걸릴 수 있습니다 경우

class Data {}; 
class Array2D: public Data{}; 
class DataAccess 
{ 
    public: 
     virtual Data* GetData(std::string sKeyName) const = 0; 
}; 
0

나는 확실하지 않다. 그렇다면 다음을 수행합니다.

template< typename T > 
struct B 
{ 
    virtual Array2D<T>* GetData(std::string sKeyName) = 0; 
}; 

struct A : public B<int> 
{ 
    virtual Array2D<int>* GetData(std::string sKeyName) 
    { 
    // implement 
    } 
}; 
4

템플릿 기반 인터페이스를 별도로 정의해야합니다.

class DataAccess { 
    template<typename T> class InnerInteface { 
     virtual Array2d<T>* GetData(std::string) = 0; 
    }; 
}; 
class OHai : public DataAccess, DataAccess::InnerInterface<float> { 
}; 
int main() { 
    DataAccess* D = new OHai; 
    if (DataAccess::InnerInterface<float>* data = 
     dynamic_cast<DataAccess::InnerInterface<float>>(D)) { 
    } 
} 

당신이 필요로 무엇을 얻을 수 있습니다. 기본 클래스를 템플릿으로 만들 수도 있지만 허용되지 않습니다.

+0

왜 DataAccess에서 상속합니까? 빈 클래스처럼 보입니다;) –

+0

@VJo : 이것은 모든 데이터 접근 자에게 공통 기본 클래스를 제공하기 때문입니다. 템플릿 만 상속하고 공통 기본 클래스는 없습니다. –

+1

''Dynamic_cast'가 작동하기 위해서는''DataAccess'를 다형성 (예 : 가상 소멸자를줌으로써)으로 만들 필요가 있습니다. –

0
  • 템플릿 기능은 가상 일 수 없습니다.
  • Array2D에는 템플릿 매개 변수가 필요합니다. 템플릿 클래스 유형이 기본값 인 경우에도 <>이 필요합니다.
3

오히려 여기 당신은 동적 기능에 대한 요구하고있다,하지만 큰 문제가 아니지만,이 인터페이스를 통해 노출되는 기능의 일부

반환 값하는 입력 매개 변수에 의해 결정됩니다 sKeyName.

C++은 정적으로 형식이 지정된 언어이므로 인수 값에 종속 된 함수의 반환 형식을 가질 수 없습니다. 당신이 살고하고자하는 경우,

struct SimpleDataAccess { 
    template <typename T> 
    array2d<T>* get_data(std::string const & which) { 
     return new array2d<T>(); 
    } 
}; 
int main() { 
    SimpleDataAccess accessor; 
    array2d<int> = accessor.get<int>("int"); // <int> at the place of call fixes 
               // the return type, not "int" ! 
} 

현재 : 시간 인 상속 무시, 당신이 제시 한 코드는 독립적으로 전달 된 인수의반환되는 배열의 유형을 결정하기 위해 사용자가 필요 즉, 호출자는 반환 형식을 알고 설정합니다. 템플릿 가상 함수를 허용하지 않는 언어의 특정 문제에 대한 대안을 제공하는 여러 가지 방법이 있습니다. 우선 마음에 떠오르는 점은 NVI 관용구를 따르고 그 중요성을 보여주는 점에서 멋지다. 데이터에 가상이 아닌 공용 템플리트 액세서를 제공하고이를 고정 리턴 유형의 가상 함수로 구현한다.

class DataAccessor { 
    virtual Type get_data_impl(std::string const &) = 0; 
public: 
    template <typename T> 
    array2d<T>* get_data(std::string const & which) { 
     Type tmp = get_data_impl(which); 
     return convert(tmp); 
    } 
}; 

우리가 Typeconvert이 무엇인지 확인할 수 있다고 가정하면, 우리는 해결책을 가지고 있습니다. 이는 NVI 관용구의 좋은 예입니다. 사용자가 제공하는 인터페이스 (공개, 비 가상)는 확장 (개인, 가상)에 필요한 인터페이스와 다릅니다.두 계약이 다르다면 사용자가 구체적인 구체화 array2d 인스턴스화에 대한 포인터를 제공해야하지만 언어에서 사용자가 내선 번호와 동일한 계약을 요구할 수는 없지만 다른 인터페이스이기 때문에 문제가되지 않습니다.

이제는 Typeconvert으로 돌아갑니다. 이 두 가지는 서로 관련되어 있으며, 여러분이 따라야 할 다른 접근법이 있습니다. 모든 array2d<T>이 파생 된에서 array2d_base 클래스를 낳게 될 것이다 구현하는 간단한 (당신이 RTTI 수 있도록 가상 소멸자를 제공하여) : 당신이 확장하거나 array2d 클래스를 변경할 수없는 경우

struct array2d_base { 
    virtual ~array2d_base() {} 
}; 
template <typename T> 
class array2d : public array2d_base { 
    // implementation 
}; 
// Type == array2d_base* 
// convert == dynamic_cast< array2d<T>* > 
template <typename T> 
array2d<T>* DataAccessor::get_data(std::string const & s) { 
    return dynamic_cast< array2d<T>* >(get_data_impl(s)); 
} 

는, 당신은 유사한 결과를 얻을 수 있습니다 타입 소거에 의해. 이것은 array2d에 RTTI를 요구하지 않고 유형 지우기 지원에서만 이점이 있습니다. 가장 간단한 구현 방법은 내부 인터페이스에 boost::any을 사용하는 것입니다.

// Type == boost::any 
// convert == boost::any_cast< array2d<T>* > 
template <typename T> 
array2d<T>* DataAccessor::get_data(std::string const & s) { 
    boost::any tmp = get_data_impl(s); 
    return boost::any_cast< array2d<T>* >(tmp); 
} 
+0

내 질문을 게시 한 후 갑작스런 긴급함으로 컴퓨터를 떠나야했습니다. 제 질문에 대답 해 주신 모든 분들께 죄송합니다. – GoldenLee

관련 문제