Ответ 1
Существует ли реальный статический полиморфизм в С++?
Абсолютно - существует три механизма статического полиморфизма: шаблоны, макросы и перегрузка функций.
Итак, как я понял, компилятор С++ делит одну определенную функцию на различное число (зависит от количества вызовов с другим типом) функций. Я прав или нет?
Это общая идея. Количество создаваемых экземпляров зависит от количества перестановок параметров шаблона, которые могут быть явно указаны как в function<int>
и function<double>
или - для шаблонов, которые используют параметры шаблона для соответствия аргументам функции - автоматически получаются из функции аргументы, например:
template <typename T, size_t N>
void f(T (&array)[N])
{ }
double d[2];
f(d); // instantiates/uses f<double, 2>()
В исполняемом двоичном изображении вы должны получить единственную копию каждого экземпляра-шаблона.
Я хочу знать, могу ли я описать вышеприведенный код как статический полиморфизм?
Не совсем.
-
template<> function
создается для двух типов-
критически, полиморфизм не используется для выбора того из двух экземпляров
function
для отправки на сайты вызовов -
тривиально, в течение таких экземпляров
typeid(T)
оценивается дляint
иdouble
и эффективно ведет себя полиморфно с точки зрения программиста (это ключевое слово компилятора, хотя реализация неизвестна)
-
-
тривиально, сочетание статического и номинально динамического (но скорее всего оптимизируемого для статического) полиморфизма поддерживает использование
std::cout
Фон - полиморфизм и генерация кода
Требование, которое я считаю решающим для полиморфизма, следующее:
-
, когда код скомпилирован (будь то "нормальный" код или каждый экземпляр шаблона или макроподстановка), компилятор автоматически выбирает (создает при необходимости) - и либо встроенные, либо вызовы - различное поведение, соответствующее типу (машинный код)
-
то есть. выбор/создание кода выполняется компилятором, основанным только на типе (типах) переменных (-ов), участвующих, а не явно жестко закодированном выбором программиста между различными именами/экземплярами функций, каждый из которых способен обрабатывать только один тип или перестановку типов
-
например,
std::cout << x;
полиморфно вызывает другой код, поскольку типx
изменяется, но все же выдает значениеx
, тогда как неполиморфныйprintf("%d", x)
обрабатываетint
, но должен быть вручную изменен наprintf("%c", x);
, еслиx
становитсяchar
.
-
Но то, что мы пытаемся достичь с помощью полиморфизма, немного более общее:
-
повторное использование алгоритмического кода для нескольких типов данных без внедрения явного определения типа и кода ветвления
- то есть без исходного кода программы, содержащего
if (type == X) f1(x) else f2(x);
-стильный код
- то есть без исходного кода программы, содержащего
-
снижение нагрузки на обслуживание, так как после явного изменения типа переменной меньшее количество последующих изменений необходимо выполнить вручную в исходном коде
Эти аспекты большего размера поддерживаются в С++ следующим образом:
-
экземпляр того же исходного кода, чтобы генерировать отличные поведения (машинный код) для некоторого другого типа strong > или перестановка типов (это аспект параметрического полиморфизма),
- фактически известный как "экземпляр" для шаблонов и "подстановка" для макросов препроцессора, но я буду использовать "экземпляр" в дальнейшем для удобства; концептуально, перекомпилировать или переинтерпретировать...
-
неявная отправка (статическая или динамическая) в отличное поведение (машинный код), соответствующий отдельным типам обрабатываемых данных.
... и несколькими незначительными способами за мой ответ в Полиморфизм в С++
Различные типы полиморфизма включают один или оба из них:
-
отправка (2) может произойти во время создания (1) для шаблонов и препроцессора макросов,
-
(1) обычно бывает при отправке (2) для шаблонов (без соответствующей полной специализации) как макросы(вид циклических, хотя макросы не рекурсивно расширяются)
-
отправка (2) может произойти без (1), когда компилятор выбирает ранее существовавшую функцию перегрузка или , или когда компилятор запускает виртуальную/динамическую отправку.
Что действительно использует ваш код?
function<int>
и function<double>
повторно используйте код шаблона function
, чтобы создать отдельный код для каждого из этих типов, поэтому вы получаете экземпляр (1), как указано выше. Но вы жестко кодируете, какие экземпляры вызова, а не компилятор, неявно выбирают экземпляр, основанный на типе некоторого параметра, т.е. Вы не используете прямое использование неявной отправки ala (2) при вызове function
. Действительно, function
не имеет параметра, который компилятор мог бы использовать для неявного выбора экземпляра шаблона.
Только экземпляр (1) не, чтобы использовать ваш код для использования полиморфизма. Тем не менее, вы достигли удобного повторного использования кода.
Итак, что было бы однозначно полиморфным?
Для того, чтобы проиллюстрировать, как шаблоны могут поддерживать отправку (2), а также создание экземпляра (1) и бесспорный обеспечивают "полиморфизм", рассмотреть следующие вопросы:
template<typename T>
void function(T t)
{
std::cout << typeid(T).name() << std::endl;
}
function(4); // note: int argument, use function<int>(...)
function(12.3); // note: double argument, use function<double>(...)
В приведенном выше коде также используется неявная отправка для соответствующего кода кода - "2.". выше - полиморфизма.
Нестандартные параметры
Интересно, что С++ предоставляет возможность создавать шаблоны с интегральными параметрами, такими как boolean, int
и константами указателей, и использовать их для всех вещей без изменения ваших типов данных и, следовательно, без какого-либо полиморфизма. Макросы еще более гибкие.
Обратите внимание, что использование шаблона в C.R.T.P. стиль НЕ является обязательным для статического полиморфизма - это пример его применения. Во время создания экземпляра компилятор демонстрирует статический полиморфизм при сопоставлении операций с реализациями в указанном параметре.
Обсуждение терминологии
Получение окончательного определения полиморфизма затруднено. wikipedia цитирует онлайн-словарь Bjarne Stroustrup "Предоставление единого интерфейса для объектов разных типов": это означает, что struct X { void f(); }; struct Y { void f(); };
уже проявляет полиморфизм, но IMHO мы получаем только полиморфизм, когда мы используем соответствие интерфейса с клиентским кодом, например. template <typename T> void poly(T& t) { t.f(); }
требует статической полиморфной отправки t.f()
для каждого экземпляра.