Un po' discutibile la scelta di usare come struttura dati sottostante un vector STL, dato che in questo modo si finisce per usare una classe template per spiegare come usare i template per classi. Insomma, si cade nella ricorsione.
Il vantaggio é che si semplifica molto il codice, rendendo forse più facile la comprensione al principiante - a patto che si fidi e non si faccia troppe domande sulla classe vector.
Anche questo capitolo mi sembra ben fatto, dando una buona introduzione alle funzionalità di base e a quelle meno comuni ma che é buona cosa sapere che ci sono e come usarle, come la specializzazione del template per uno specifico tipo e l'uso di argomenti di default nella definizione di un template.
Qui riporto solo il codice per un esempio di base, con la definizione della classe generica Stack:
#include <vector>
#include <stdexcept>
#include <iostream>
using namespace std;
template<class T>
class Stack {
private:
vector<T> elements;
public:
void push(T const& element) {
// append copy of passed element
elements.push_back(element);
}
void pop();
T top() const;
bool empty() const {
return elements.empty();
}
};
template<class T>
void Stack<T>::pop()
{
if (elements.empty()) {
throw out_of_range("Stack<>::pop(): empty stack");
}
elements.pop_back();
}
template<class T>
T Stack<T>::top() const
{
if (elements.empty()) {
throw out_of_range("Stack<>::top(): empty stack");
}
return elements.back();
}
Notiamo come pop() e top() possano tirare eccezioni nel caso si cerchi di chiamarle su uno stack vuoto. Il codice che usa questa classe, perciò, dovrà tenere conto di questa possibilità:
try {
Stack<string> stringStack;
stringStack.push("hello");
cout << stringStack.top() << endl;
stringStack.pop();
stringStack.pop();
}
catch (const exception& ex) {
cerr << "Exception: " << ex.what() << endl;
}
Nessun commento:
Posta un commento