2013-09-09 2 views
0

Учитывая следующие классы:Наследование, способствуют базовые члены класса

template <typename DataType, size_t Dimensions> 
class Vector : public std::array<DataType, Dimensions> { 
//stuff 
}; 

template <typename DataType> 
class Vector2 : public Vector<DataType, 2> { 
//2d specific stuff 
}; 

template <typename DataType, size_t Dimensions> 
class Line { 
public: 
    Vector<DataType, Dimensions>& min(); 
    Vector<DataType, Dimensions>& max(); 

private: 
    Vector<DataType, Dimensions> m_min; 
    Vector<DataType, Dimensions> m_max; 
}; 

template <typename DataType> 
class Line2 : public Line<DataType, 2> { 
//2d specific stuff 
}; 

Какой самый лучший способ иметь min() и max() при вызове на Line2, вернуть Vector2&, а не Vector&? Могу ли я продвигать m_min и m_max до Vector2 в пределах Line2? Или иначе переопределить их и по-прежнему иметь функцию базового класса Line?

+0

Частичная специализация по шаблону. – aaronman

+0

Почему 'Line2' даже нужно унаследовать от' Line', если у них есть несовместимые внешние интерфейсы? – millimoose

+0

У меня было это как частичная специализация по шаблону, но было много повторного кода. Должны ли они совместно использовать базовый класс impl? – OmnipotentEntity

ответ

1

Я думаю, что предложение Kerrek о использовании частичной специализации шаблона вместе с общим базовым классом является разумным, но вы должны применять техника для векторного типа:

template <typename DataType, size_t Dimensions> 
class VectorBase : public std::array<DataType, Dimensions> { 
    // things common to all vectors here 
}; 

template <typename DataType, size_t Dimensions> 
class Vector : public VectorBase<DataType, Dimensions> { 
    // nothing here 
}; 

template <typename DataType> 
class Vector<DataType, 2> : public VectorBase<DataType, Dimension> { 
    // 2d specific stuff here, so for example: 
    DataType& x() { return at(0); } 
    DataType& y() { return at(1); } 
}; 

template <typename DataType, size_t Dimensions> 
class Line { 
public: 
    Vector<DataType, Dimensions>& min(); 
    Vector<DataType, Dimensions>& max(); 

private: 
    Vector<DataType, Dimensions> m_min; 
    Vector<DataType, Dimensions> m_max; 
}; 

Теперь вы можете сделать:

Line<double, 2> myLine; 
double foo = myLine.max().x(); 

Вы могли бы также применить технику к классу Line, но это было бы полезно только для добавления функций, характерных для 2D-линий, таких как, возможно, вычисление диаграммы Вороного. Вам не нужна специализация Line, чтобы Line возвращал 2D-вектор - это происходит автоматически.

+0

Спасибо, это похоже на лучшее решение. :) – OmnipotentEntity

1

Обычный подход сломать шаблон вниз в общие и специальные части:

template <typename T, size_t N> struct LineCommon { /* ... */ }; 

template <typename T, size_t N> struct Line : LineCommon<T, N> 
{ 
    Vector<T, N> & min(); 
    Vector<T, N> & max(); 
}; 

template <typename T> struct Line2 : LineCommon<T, 2> 
{ 
    Vector2<T> & min(); 
    Vector2<T> & max(); 
}; 
+0

Какой класс будет содержать 'm_min' и' m_max'? – OmnipotentEntity

+0

@OmnipotentEntity: Где бы вы ни думали, он подходит лучше всего. –

+0

Причина, по которой я прошу, я не думаю, что могу поместить их в базовый класс; однако базовый класс должен будет получить к ним доступ. – OmnipotentEntity

0

немного обновления, это то, что я ликвидируется делать:

Поскольку некоторые из функций, которые бы принадлежали в классе Base, необходимом для возвращения копии вектора, я нуждался бы использовать CRTP. Но мне действительно не понравился код скелета, необходимый для этого. Это было слишком сложно.

template <typename derived> 
struct test_base { 
    derived baz() { return *static_cast<derived *>(this); } 
}; 

template <int N> 
    struct test : public test_base<test<N>> { 
}; 

template <> 
struct test<2> : public test_base<test<2>> { 
    test bar() { return *this; } 
}; 

int main() { 
    test<1> a = {}; 
    test<2> b = {}; 

    auto c = a.baz(); 
    auto d = b.baz(); 
    auto e = b.bar(); 

    return 0; 
} 

Таким образом, в стремлении искать льстить иерархии я прибегли к некоторому шаблону обмане:

#include <type_traits> 

template <int N> 
struct test { 
    void foo() {} 

    template <int P=N> 
    typename std::enable_if<P == 2 && P == N>::type bar() {} 

    template <int P=N> 
    typename std::enable_if<P == 3 && P == N>::type baz() {} 
}; 

int main() { 
    test<1> a = {}; 
    test<2> b = {}; 
    test<3> c = {}; 

    a.foo(); 
    b.foo(); 
    c.foo(); 

    b.bar(); 
    c.baz(); 

    return 0; 
} 

Что мне казалось, чтобы быть чистое решение. И это также позволяет мне записывать такие функции, как:

template <int P=N> 
typename std::enable_if<P >= 2 && P == N>::type x() { return Base::operator[](0); } 
Смежные вопросы