В чем различие полиморфизма и перегрузки?
Перегрузка это и есть одно из проявлений полиморфизма. 
Всего есть различные виды полиморфизма (ответ больше для C# и Java, если для c++ что-то не так, поправьте меня): 
* динамический: это когда программа во время выполнения решает какой код исполнять. Это происходит при наследовании: когда ты переопределяешь функцию в другом классе (виртуальные методы, абстрактные)
* статический: на стадии компиляции все известно, это как раз перегрузка методов. Компилятор исходя из аргументов выбирает нужный метод
При перегрузке ты можешь перегрузить функцию для разных количества и типов аргументов, но для каждого случая нужно отдельно определять функцию.int plus(int a, int b) {return a + b;}
float plus(float a, float b) {return a + b;}
double plus(double a, double b) {return a + b;}
unsigned long long plus(unsigned long long a, unsigned long long b) {return a + b;}
// выбьет ошибку для любого другого типа, кроме int, float, double, unsigned long long
При использовании шаблонов ты определяешь шаблон только однажды, а компилятор сам сгенерирует определение стольких функций сколько потребуется.template<typename T>
T plus(T a, T b) {return a + b;}
// Работает для любых типов, которые определяют opeator+
P.S. По сути, и перегрузка и шаблоны это и есть средства полиморфизма.