class template (tsz. class templates)
Képzeljük el, hogy egy Stack
osztályt szeretnénk írni, amely egész számokat (int
) tárol. Ha később stringeket vagy lebegőpontos számokat is szeretnénk benne tárolni, akkor újra meg kellene írni az egész osztályt más típusra. Ehelyett az osztály sablonok lehetővé teszik, hogy egyetlen általános osztályt írjunk, amit majd bármilyen típusra “testre szabhatunk”.
template <typename T>
class MyClass {
private:
T data;
public:
MyClass(T value) : data(value) {}
void show() const {
std::cout << "Data: " << data << std::endl;
}
};
template <typename T>
: Ez a sablonfej. A T
egy típusparaméter, amit a felhasználó határoz meg az osztály példányosításakor.T data
: Ez azt jelenti, hogy a data
változó típusa a felhasználótól függ.MyClass<int> obj1(42); // T = int
MyClass<std::string> obj2("hi"); // T = std::string
Több típusparamétert is használhatunk:
template <typename T, typename U>
class Pair {
T first;
U second;
public:
Pair(T a, U b) : first(a), second(b) {}
void print() const {
std::cout << first << ", " << second << std::endl;
}
};
Használat:
Pair<int, std::string> p(1, "alma");
p.print(); // 1, alma
Az osztály sablon definícióját és a tagfüggvények implementációját nem szokás külön fájlba tenni, mivel a fordító csak akkor generálja le a kódot, amikor konkrét típusra példányosítjuk az osztályt. Ha mégis külön fájlba tesszük, célszerű a .h
fájlba tenni minden sablonfüggvényt is, vagy .tpp
fájlt használni.
template <typename T>
class Stack {
std::vector<T> elems;
public:
void push(const T& elem) {
elems.push_back(elem);
}
void pop() {
if (!elems.empty())
elems.pop_back();
}
T top() const {
return elems.back();
}
bool empty() const {
return elems.empty();
}
};
Használat:
Stack<int> s;
s.push(10);
s.push(20);
std::cout << s.top(); // 20
template <typename T = int>
class MyContainer {
T value;
public:
MyContainer(T v = 0) : value(v) {}
void print() const { std::cout << value << std::endl; }
};
MyContainer<> c1; // int-ként viselkedik
MyContainer<double> c2; // double típus
Néha egy adott típushoz más viselkedést akarunk:
template<>
class MyClass<std::string> {
public:
void show() const {
std::cout << "Ez egy string!" << std::endl;
}
};
Ez a teljes specializáció.
template <typename T, typename U>
class MyPair {};
template <typename T>
class MyPair<T, int> {
// akkor specializált, ha második paraméter int
};
template <typename T>
class Base {
public:
void show() { std::cout << "Base" << std::endl; }
};
template <typename T>
class Derived : public Base<T> {
public:
void print() { std::cout << "Derived" << std::endl; }
};
template<typename... Args>
)
Az STL (Standard Template Library) legtöbb konténerosztálya (pl. vector
, map
, set
) class template-ként van implementálva:
std::vector<int> v;
std::map<std::string, int> m;
A C++ class template-ek lehetővé teszik generikus, típusfüggetlen osztályok írását. Ez kulcsfontosságú az STL és más modern C++ könyvtárak működésében. A sablonok használata nagyban növeli a kód újrahasznosíthatóságát és általánosíthatóságát, ugyanakkor óvatosan kell bánni velük, mivel bonyolultabbá tehetik a hibaelhárítást.