Dariusz Wardowski
Wielokrotne wykorzystywanie kodu
Poza dziedziczeniem oraz kompozycją klas, język C++ udostępnia kolejne narzędzie w postaci szablonów, które służą do wielokrotnego wykorzystywania kodu.
Szablony służą do tworzenia ogólnych deklaracji klas (lub funkcji). W ten sposób realizowana jest koncepcja tzw. typów sparametryzowanych. Typ jest argumentem przekazywanym do ogólnego wzorca klasy lub funkcji.
Stos<int> s1;
Stos<double> s2;
Stos<Pracownik> s3;
Klasa Punkt i klasa … Punkt
class Punkt {
private:
int x, y;
public:
Punkt();
Punkt(int,int);
int getX();
int getY();
void setXY(int,int);
};
class Punkt {
private:
double x, y;
public:
Punkt();
Punkt(double,double);
double getX();
double getY();
void setXY(double,double);
};
Dobrym rozwiązaniem jest zamiana powyższych klas na jedną definicję szablonu, posługując się tzw. parametrem typów.
Szablon klasy
#ifndef PUNKTTP_H_
#define PUNKTTP_H_
template <typename T>
class Punkt {
private:
T x, y;
public:
Punkt();
Punkt(T,T);
T getX();
T getY();
void setXY(T,T);
void wypisz();
};
template <typename T>
Punkt<T>::Punkt() {
x = y = 0;
}
template <typename T>
Punkt<T>::Punkt(T _x, T _y) {
x = _x;
y = _y;
}
template <typename T>
T Punkt<T>::getX() {
return x;
}
template <typename T>
T Punkt<T>::getY() {
return y;
}
template <typename T>
void Punkt<T>::setXY(T _x, T _y) {
x = _x;
y = _y;
}
#endif
Konkretyzacja szablonu
Chcąc wygenerowad klasę na podstawie zdefiniowanego szablonu należy jawnie określid typ parametru (tzn. dokonad jawnej konkretyzacji typu).
#include <iostream>
#include "Punkttp.h"
using namespace std;
int main() {
Punkt<int> p(3,2);
cout << p.getX();
Punkt<double> z(3.2,2.1);
z.setXY(5.01,3);
return 0;
}
Konkretyzując klasę możemy użyd zarówno typu wbudowanego jak i obiektu jakiejś klasy.
Szablon tablicy
template <typename Typ, int n>
class TabTP {
private:
Typ tablica[n];
public:
TabTP() {};
explicit TabTP(Typ &);
virtual Typ & operator[](int);
};
Template<typename Typ, int n>
TabTP<Typ,n>::TabTP(Typ & w) {
for (int i=0; i<n; i++) tablica[i]=w;
}
Template<typename Typ, int n>
Typ & TabTP<Typ,n>::operator[](int i) {
if (i<0 || i>=n) {cerr << „Blad!”; exit(1);}
return tablica[i];
}
Typ – argument typu n – argument wyrażenia
TabTP<double,10> t1;
TabTP<int,100> t2;
TabTP<char,20> t3;
Nie-typy, czyli argumenty wyrażenia
Argumenty wyrażenia podlegają następującym ograniczeniom:
-Typ argumentu może byd: całkowity, wyliczeniowy, referencją, wskaźnikiem - W kodzie szablonu nie można zmieniad wartości argumentu
- W kodzie szablonu nie można pobierad adresu argumentu
- Przy konkretyzacji szablonu wartośd użyta dla argumentu powinna byd stałą
Dziedziczenie i szablony
Szablony klas mogą służyd do tworzenia klas, które będą pełniły rolę klas macierzystych.
template <typename T1>
class A {
private:
T x;
… };
template <typename T2>
class B: public A<T2>
{
… }
Klasy szablonowe jako składowe innych klas
Klasy szablonowe mogą służyd jako składowe dla innych klas szablonowych.
template <typename T1>
class A {
… };
template <typename T2>
class B {
A<T2> y;
… }
Klasa szablonowa jako argument typu
Klasy szablonowe mogą stanowid argument typu dla innych szablonów.
template <typename T1>
class A {
… };
template <typename T2>
class B {
… }
A< B<int> > x;
Inny przykład:
Tablica < Stos<double> > TAB; //tablica stosów liczb zmiennoprzecinkowych
Rekurencja w szablonach
Konkretyzując szablon możemy korzystad z rekurencji:
TabTP< TabTP<double,10>, 20> T;
T jest dwudziestoelementową tablicą, w której każdy element jest dziesięcioelementową tablicą liczb zmiennoprzecinkowych.
Więcej niż jeden argument typu
W języku C++ możemy używad szablony, które posiadają więcej niż jeden argument typu.
Korzystając z tej możliwości możemy utworzyd klasę do przechowywania dwóch elementów różnych typów.
template <typename T1, typename T2>
class Pair {
private: T1 x, T2 y;
public:
T1 & first(const T1 & f) {x = f; return x;};
T2 & second(const T2 & s) {y = s; return y;};
T1 first() const {return x;}
T2 second() const {return y;}
Pair(const T1 & f, const T2 & s) : x(f), y(s) {}
Pair(){}
};
Użycie szablonu Pair
Pair<int,double> points[4] = {
Pair<int,double>(1,1.2), Pair<int,double>(-4,1.0), Pair<int,double>(100,0.45), Pair<int,double>(12,1.2) };
Pair<char *, int> adresy[2] = {
Pair<char *, int>(„ul. Banacha”,22), Pair<char *, int>(„ul. Zielona”,13) };