2009-12-10 3 views
17

Что такое полиморфизм времени компиляции и почему он применяется только к функциям?Что такое полиморфизм времени компиляции и почему он применяется только к функциям?

+6

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

+2

Можете ли вы описать противоречие, которое видите? - Возможно, это помогает ответить на фактический вопрос, который у вас есть. – johannes

+1

В моем учебнике есть какая-то двусмысленность, или я не понимаю, что я читаю, поэтому я решил, что прошу здесь. – ihtkwot

ответ

17

Возвращение назад, когда «полиморфизм времени компиляции» означает перегрузку функции. Это относится только к функциям, потому что они все, что вы можете перегрузить.

В текущем C++ шаблоны меняют это. Нил Баттерворт уже привел один пример. Другой использует специализированную специализацию. Например:

#include <iostream> 
#include <string> 

template <class T> 
struct my_template { 
    T foo; 
    my_template() : foo(T()) {} 
}; 

template <> 
struct my_template<int> { 
    enum { foo = 42 }; 
}; 

int main() { 
    my_template<int> x; 
    my_template<long> y; 
    my_template<std::string> z; 
    std::cout << x.foo << "\n"; 
    std::cout << y.foo << "\n"; 
    std::cout << "\"" << z.foo << "\""; 
    return 0; 
} 

Это должно дать 42, 0 и "" (пустая строка) - мы получаем структуру, которая действует по-разному для каждого типа.

Здесь у нас есть «полиморфизм времени компиляции» классов вместо функций. Я полагаю, что если вы хотите аргументировать эту точку зрения, вы можете утверждать, что это хотя бы частично результат конструктора (функции) хотя бы в одном случае, но в специализированной версии my_template нет , есть конструктор.

Редактировать: Что касается того, почему это полиморфизм. Я поставил «полиморфизм времени компиляции» в кавычки по какой-то причине - он несколько отличается от обычного полиморфизма. Тем не менее, мы получаем эффект, подобный тому, что мы могли бы ожидать от перегрузки функций:

int value(int x) { return 0; } 
long value(long x) { return 42; } 

std::cout << value(1); 
std::cout << value(1L); 

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

+1

Термин компиляция полиморфизма времени немного расплывчата, можете ли вы подробнее рассказать о том, как вы думаете, что ваш пример полиморфен? Я все еще нахожусь на заборе, потому что это или не является полиморфизмом. Я бы предположил, что полиморфной частью этого примера является перегрузка оператора '<<' для 'std :: ostream'. Следует ли рассматривать экземпляр шаблона как своего рода абстрактную функцию, где тип является аргументом? –

+0

Как бы вы утверждали, что полиморфизм не применяется? Полимофизм означает либо «много форм». В примерах (и при перегрузке функций) один и тот же переключатель функций приводит к нескольким различным «формам» функции. –

6

время компиляции полиморфизм это термин, который относится к шаблону программирования C++. Например, во время компиляции вы определить фактический тип станд :: вектор тем, что он содержит:

std::vector <int> vi; 
std::vector <std::string> vs; 

Я не знаю, почему вы думаете, что она ограничена функциями.

+0

В основном из-за того, что мне говорили в моем классе, он ограничивался функциями. Я не совсем понимаю, почему он ограничен только функциями. – ihtkwot

+1

@ Нейл Я согласен с тобой. Шаблоны классов также, похоже, отображают полиморфизм времени компиляции. – captonssj

13

С компиляцией времени полиморфизма один обычно означает тот факт, что вы можете иметь несколько функций с тем же именем и компилятором будет выбрать во время компиляции, который один для использования в зависимости от аргументов:

void foo(int x); 
void foo(float y); 

//Somewhere else 
int x = 3; 
foo(x); //Will call first function 
float y = 2; 
foo(y); //Will call second function 

Функции foo считается перегруженным. Различные типы экземпляров шаблона также можно назвать полиморфизмом времени компиляции.

+0

Проклятье, избили меня. – wheaties

+0

Как насчет шаблонов классов? Компилятор выбирает, какую версию класса следует создавать на основе типа T, который мы предоставляем, так ли это означает, что шаблоны классов также отображают полиморфное поведение времени компиляции? – captonssj

+0

@captonssj, я бы сказал, что да, они это делают. – Omnifarious

6

Вещь, применимая только к функциям, является вычитанием параметра шаблона. Если у меня есть шаблон функции:

template <typename T> 
void foo(T &t); 

Тогда я могу сделать int a = 0; foo(a);, и это будет эквивалентно int a = 0; foo<int>(a);. Компилятор работает, я имею в виду foo<int>. По крайней мере, выясняется, что он должен использовать foo<int> - если это не то, что я имел в виду, тогда мне не повезло, и я мог бы написать foo<unsigned int>(a); или что-то еще.

Однако, если у меня есть шаблон класса:

template <typename T> 
struct Foo { 
    T &t; 
    Foo(T &t) : t(t) {} 
    T &getT() { return t; } 
}; 

Тогда я не могу сделать int a = 0; Foo(a).getT();. Я должен указать Foo<int>(a). Компилятору не разрешено работать, я имею в виду Foo<int>.

Итак, вы можете сказать, что шаблоны классов «менее полиморфны», чем шаблоны функций. Полиморфизм обычно означает, что вам не нужно писать код, чтобы сделать тип вашего объекта явным. Шаблоны функций позволяют это (в данном конкретном случае), а шаблоны классов - нет.

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

Но вы все еще можете сделать другие виды полиморфизма классов:

template <typename T> 
struct Foo { 
    T &t; 
    Foo(T &t): t(t) {} 
    void handleMany(int *ra, size_t s) { 
     for (size_t i = 0; i < s; ++i) { 
      t.handleOne(ra[i]); 
     } 
    } 
}; 

Это, как правило, также называется время компиляции полиморфизм, потому что, насколько автор шаблона обеспокоен, t.handleOne может быть что угодно, и что это будет, когда это необходимо, будет разрешено «позже» в компиляции при создании экземпляра Foo.

+0

Я думаю, что это полезно в соответствии со стандартным комитетом, потому что они решили обойти эту конкретную проблему с реализацией std :: mem_fun/std :: mem_fun_t.В основном то, что они сделали: шаблон <имяТипа _Tx> станд :: mem_fun_t <_Tx> mem_fun (Const _Tx & т) { возвращение станд :: mem_fun_t <_Tx> (т); } –

+0

Да, и то же самое с итераторными адаптерами: 'back_inserter' возвращает' back_insert_iterator'. Когда я сказал «и», я имел в виду «это список», а не «все это правда». Я думаю, что (а) тоже маловероятно, так что это либо (с), либо «без уважительной причины». –