Подтвердить что ты не робот

С++ шаблон duck-typing vs чистое наследование виртуального базового класса

Каковы руководящие принципы для выбора между утиным типом шаблона и наследованием чистого виртуального базового класса? Примеры:

// templates
class duck {
    void sing() { std::cout << "quack\n"; }
};

template<typename bird>
void somefunc(const bird& b) {
    b.sing();
}

// pure virtual base class
class bird {
    virtual void sing() = 0;
};

class duck : public bird {
    void sing() { std::cout << "quack\n"; }
}

void somefunc(const bird& b) {
    b.sing();
}
4b9b3361

Ответ 1

С помощью шаблона утиного ввода вы выполняете статический полиморфизм. Таким образом, вы не можете делать такие вещи, как

std::vector<bird*> birds;
birds.push_back(new duck());

Однако, поскольку вы полагаетесь на ввод времени компиляции, вы немного более эффективны (ни один виртуальный вызов не подразумевает динамическую отправку (база для динамического типа)).

Ответ 2

Если "характер шаблона" вещей широко распространен, все в порядке с вами, шаблоны ( "компиляция времени утиного ввода" ) могут дать вам потрясающую скорость (избегая "уровня косвенности", который подразумевается при вызове виртуальной функции), хотя, возможно, по какой-то цене в области памяти (теоретически, хорошие реализации на С++ могли бы избежать накладных расходов памяти, связанных с шаблонами, но я не уверен, что такие высококачественные компиляторы обязательно будут доступны на всех платформах, где вам нужно порт;-). Таким образом, по крайней мере прагматично, это что-то вроде компромисса скорости/памяти. Если операции, которые вы делаете, настолько супер-медленны, как I/O, то, возможно, относительно небольшое увеличение скорости от предотвращения виртуального вызова не является существенным для вашего использования.

Ответ 3

Время компиляции и время выполнения. Если вы хотите привязать время компиляции, вам нужно использовать шаблоны. Если вы не знаете типы во время компиляции, вы должны использовать виртуальное наследование.

Ответ 4

Это две совершенно разные вещи. Один из них не является альтернативой другому. Функция шаблона обеспечивает общую операцию somefunc(), которая применяется ко всему классу типов, а не только к птицам. Тип его параметра должен быть известен во время компиляции. Виртуальный метод обеспечивает полиморфную работу во время выполнения, характерную для птиц. Точный тип параметра (this) не обязательно должен быть известен во время компиляции.

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

(btw, термин "утиная печать" используется здесь неправильно. Ни один из подходов не является утиным типом. Вы должны отбросить фразу из своего лексикона С++.)

Ответ 5

@Джон прав. Если у вас есть два параметра ковариантного типа, у вас нет выбора, вы должны использовать шаблоны. Объектно-ориентированные методы обеспечивают диспетчеризацию во время выполнения, но доступны только для типов, методы которых имеют не более одного варианта аргумента (объект).

Наиболее интересные проблемы связаны с отношениями, которые являются N-арными с N > 1, поэтому у вас обычно нет выбора, кроме как использовать шаблоны. Изучите стандартную библиотеку, чтобы узнать, какой метод используется больше всего.