2010-08-04 6 views
0

Я имею следующую структуру:C++. Наследование v Сдерживание для Шаблонного класса

template <typename T> 
struct Odp 
{ 
    T m_t; 
}; 

Я хочу специализироваться, так что я могу добавить оператор поэтому тип играет хорошо с наборами STL. (Я не могу изменить Odp непосредственно, это унаследованный код.) Вот два метода, которые я вижу сделать это:

struct Ftw : public Odp<int> 
{ 
    bool operator==(const Ftw& rhs) 
    { 
     return m_t == rhs.m_t; 
    } 
}; 

struct FtwContain 
{ 
    Odp<int> odp; 
    bool operator==(const FtwContain& rhs) 
    { 
     return odp.m_t == rhs.odp.m_t; 
    } 
}; 

Есть ли основание предпочесть второй над первым? Первый способ, как представляется, позволяет более чистый код:

Ftw ftw; 
ftw.m_t = 2; 

FtwContain ftwContain; 
ftwContain.odp.m_t = 2; 

(. Кроме того, есть шанс, что я запутался о том, что термин «шаблон специализации» средства)

+1

Речь идет о наследовании против композиции, а не о специализации шаблона. Специализация - это то, где вы определяете другую версию шаблона для конкретного аргумента шаблона; например, 'template <> struct Odp {long m_t;};' означает, что 'Opd ' будет содержать 'long', а не' int'. –

ответ

0

Почему не получения ODP к MyOdp, положить ваш (общий) код в нем и просто сделать Ftw из Odp (как в вашем первом примере) или с помощью typedef? Кстати, это не специализация, а инициация. Специализация шаблона - это когда вы (re) определяете метод для определенного типа.

0

Обычно я предпочитаю композицию над наследованием, но это действительно зависит от дизайна. Является ли Ftw типом Odp или содержит Ftw Odp.

Я бы не выбрал метод, основанный на более чистом коде (так как это не так уж и важно), я бы выбрал метод, основанный на концептуальной зависимости между Odp и Ftw.

1

Вы можете действительно смутить терминологию. (Partial) template specialization обычно ссылается на конкретную реализацию шаблонного класса/структуры для выделенного типа. То есть вы можете иметь общий шаблонный класс Hash, который предоставляет значения хэша для типов с использованием метода getHash. Затем этот метод имеет общую реализацию, которая не заботится о типе, и, возможно, специальную реализацию для хэш-значений на строках:

// default implementation 
template<typename T> class Hash { int getHash(T val) { return val; } } 
// string implementation 
template<> class Hash<std::string> { int getHash(std::string val) { return val[0] || val[1]; } } 

Что вы делаете в Уре примерах, однако, не специализация шаблона, но наследование (в первом подходе) и использование шаблона Odp в качестве клиента. В обоих случаях, если кто-либо использует шаблон Odp, как в Odp<int> odp, будет использоваться исходная реализация, которая может быть не такой, какой вы хотите. Если вы будете использовать надлежащую специализацию шаблона, Odp<int> будет ссылаться на ваш специализированный код.

7

Я не верю, что есть необходимость в создании нового типа - просто написать свободную функцию:

template <typename T> 
bool operator==(const Odp<T> & a, const Odp <T> & b) { 
    return a.m_t == b.m_t; 
} 
0

В случае, если вы упомянули, я думаю, что свободная функция, возможно, самым чистым способом с наименьшее количество проблем с перестройкой. Поместите эту бесплатную функцию в отдельный файл cpp, и вам должно быть хорошо идти.

Возможные случаи для вывода

  1. Вы хотели бы получить, если вы должны передать свой объект в некоторую функцию, которая принимает тип базового класса
  2. ли производный класс типа первого типа. Если да, да (например, плотоядное животное - животное) 3.Если в базовом классе есть защищенные методы, которые вы хотите использовать в производном классе. Я не уверен, что указанная вами структура - это полный код или только соответствующий раздел. Если это не так, это может быть одной из причин, по которой вы хотите получить.

Возможные случаи для содержания

  1. Вы просто хотите использовать класс, и нет вне-отношения. TBH, можно также моделировать объекты с содержимым is-a, где в типе контейнера действует как прокси-сервер для содержащегося типа (я думаю, что это шаблон проектирования, но я не уверен в имени шаблона).
  2. Вы заинтересованы в использовании только одного или двух методов и не беспокоитесь об общем состоянии
  3. Этот объект никогда не передается ни на какой другой интерфейс, для которого требуется базовый класс (всегда можно передать содержащийся объект, но это выглядит грязно. Кроме того, бросать в виртуальные функции, и все по-другому. Извините, я отвлекся).
0

Как Нейл упоминает, operator== вполне может быть свободной функцией.

Другой вариант: стандартная библиотека позволяет использовать пользовательские предикатные объекты. В этом случае:

#include <set> 

template <typename T> 
struct Odp 
{ 
    T m_t; 
}; 

struct CompareOdp 
{ 
    template <class T> 
    bool operator() (const Odp<T>& a, const Odp<T>& b) const 
    { 
     return a.m_t < b.m_t; 
    } 
}; 

int main() 
{ 
    std::set<Odp<int>, CompareOdp > my_set; 
    Odp<int> value = {10}; 
    my_set.find(value); 
} 

(Не уверен, может ли она быть лучшей идеей, чтобы сделать весь предикат шаблона Создание только operator() шаблон, кажется, чтобы сделать его проще в использовании, так как она оставляет больше вещей, к. компилятор, чтобы выяснить. не уверен, что если бы он мог поддержать огнь в некоторых сценариях.)


отметить также, что зЬй :: набор использует предикат для заказа (по умолчанию std::less<X>), а не для испытаний равенства.

Смежные вопросы