Funkcje wzorcowe stosujemy jeśli potrzebujemy funkcji, które działają w ten sam sposób, a różnią się tylko typami używanych zmiennych. Roważmy na przykład funkcję
int max(int a, int b) {która zwraca większą z dwóch liczb. Jeśli potrzeba nam dodatkowo funkcji max, która porównuje liczby typu np. double musimy napisać drugą funkcję:
if(a>b) return a;
else return b;
}
double max(double a, double b) {Nie różni się ona od poprzedniej niczym poza typami argumentów (i zwracanej wartości). Jak zapobiec pisaniu powtarzającego się kodu? Można zdefiniować funkcję wzorcową max.
if(a>b) return a;
else return b;
}
template <class T>Teraz max(a,b) będzie działać dla dowolnych typów, dla któych zdefiniowany jest operator porównania >.
T max(T a, T b) {
if(a>b) return a;
else return b;
}
Uwagi:
class Wektor {Co zrobić jeśli będziemy potrzebować wektorów o współrzędnych całkowitych (albo zespolonych)? Można napisać nową klasę (która będzie wyglądać dokładnie tak samo jak poprzednia), ale prościej jest stworzyć wzorzec klasy, tak jak poniżej:
public:
Wektor(double _x, double _y): x(_x), y(_y) {}
Wektor operator+(Wektor w) { return Wektor(x+w.x, y+w.y); }
double operator*(Wektor w) { return x*w.x+y*w.y); }
void wypisz();
private:
double x, y;
};
void Wektor::wypisz() {
cout << "(" << x << "," << y << ")";
}
template <class T>Wzorce klas definiuje się tak samo jak klasy, z tym, że definicję należy poprzedzić słowem template z parametrem (listą parametrów); to samo dotyczy jej metod definiowanych na zewnątrz klasy. Teraz już można używać klas Wektor<double>, Wektor<int>, Wektor<zespolona> do reprezentowania odpowiednio wektorów rzeczywistych, całkowitych i zespolonych (zakładając, że klasa zespolona została zdefiniowana wcześniej).
class Wektor {
public:
Wektor(T _x, T _y): x(_x), y(_y) {}
Wektor operator+(Wektor w) { return Wektor(x+w.x, y+w.y); }
T operator*(Wektor w) { return x*w.x+y*w.y); }
void wypisz();
private:
T x, y;
};
template <class T>
void Wektor<T>::wypisz() {
cout << "(" << x << "," << y << ")";
}