Požiadavky:
Aby to bol kontainer, musí mať v sebe typy
value_type, reference_type, const_reference_type, size_type, difference_type, iterator a const_iterator
a funkcie
gpole(), const_iterator begin() const, iteator begin(), const_iterator end() const, iterator end(), size_type size(), bool empty().
Ďalej to malo mať funkciu void push_back(const T&) a pôvodne aj funkcie T& at(int index) a const T& at(int index) const. Tie boli neskôr vymenené za T & write(int index) a T read(int index) const.
Celý kontainer sa mal dať vypísať do streamu a načítať zo streamu (gpole<int, 5> a; cin >> a; cout << a;).
Funkcie robia na našom kontajneri gpole to isté, čo na vektore.
read mala vyhadzovať výnimku, ak sme mimo poľa, write malo vyhodiť výnimku, ak sme pod dolným indexom, ináč (v prípade potreby) roztiahnúť pole a prvky "v strede" vyplniť prvkami T().
Typy v kontajneri gpole sa vyrieši rýchlo (to vlastne bolo povedané pri zadaní):
Kód: Vybrat vše
typedef T value_type;
typedef T& reference_type;
typedef const T& const_reference_type;
typedef int size_type;
typedef int difference_type;
Kód: Vybrat vše
typedef typename std::vector<T>::iterator iterator;
typedef typename std::vector<T>::const_iterator const_iterator;
Funkcia bool empty() bola rovno predpísaná: {return size() == 0;}.
Na výpis do streamu bola požiadavka, že ak vypíšeme gpole do súboru, tak sa z neho musí dať načítať (čiž vo výpise nejak oddeľovať prvky, najlepšie medzerami). Výpis jedného prvku T p je cout << p; O implementáciu << pre T sa stará ten, čo používa našu šablónu.
Na výpis teda použijeme:
Kód: Vybrat vše
template <typename T, int n> std::ostream & operator<<(std::ostream & s, const gpole <T, n> & pole)
No a ešte môj program. Rozhodol som sa gumové pole si implementovať sám (nepoužiť vector). Pôvodne som myslel, že vyrobím aj rozumnú funkciu at() - pozri posledný slajd ku stringom v Bednárkovych slajdoch - ale nejak to nevyšlo. Je teda zakomentovaná (skúste to opraviť, zaujíma ma to). Tiež som mal problém s označením operátoru ako friend, takže je to trochu "prasácke" (verejné dátové položky), ale bolo to uznané.
Na začiatku je nejaká testovacia trieda - mali sme šablónu otestovať nie len na vstavaných typoch.
Takže program:
Kód: Vybrat vše
#include <iostream>
#include <stdexcept>
#include <algorithm>
class testovacia_trieda{
public:
testovacia_trieda():a(0){}
testovacia_trieda(int a_){
a=a_;
}
bool operator<(const testovacia_trieda & b){
return a < b.a;
}
int a;
};
std::ostream & operator<<(std::ostream & s, const testovacia_trieda & a){
s << a.a;
return s;
}
std::istream & operator>>(std::istream & s, testovacia_trieda & a){
s >> a.a;
return s;
}
template <typename T, int dolny_index> class gpole{
public:
typedef T value_type;
typedef T& reference_type;
typedef const T& const_reference_type;
typedef int size_type;
typedef int difference_type;
typedef T * iterator;
typedef const T * const_iterator;
enum {DOLNY_INDEX = dolny_index, MINIM_ALOK = dolny_index>0?dolny_index+10:10};
int pocet_prvkov;
int alokovane;
T * pole;
int size(){
return pocet_prvkov;
}
bool empty(){
return pocet_prvkov == 0;
}
iterator begin(){
return pole;
}
iterator end(){
return pole+pocet_prvkov;
}
const_iterator begin() const{
return pole;
}
const_iterator end() const{
return pole+velkost;
}
gpole(){
alokovane = MINIM_ALOK;
pole = new T[MINIM_ALOK];
pocet_prvkov = 0;
}
void push_back(const T & novy_prvok_){
if (alokovane == pocet_prvkov+1){ //TODO: skontroluj podmienku!!
T* pomocne_pole = 0;
try{
pomocne_pole = new T[alokovane * 2];
}catch(...){ //TODO: Aku vynimku vracia new?
std::cerr << "Malo pamate! Vynimka." << std::endl;
return;
}
alokovane = alokovane * 2;
for (int i = 0; i<pocet_prvkov; i++){
pomocne_pole[i] = pole[i];
}
delete pole;
pole = pomocne_pole;
}
pole[pocet_prvkov] = novy_prvok_;
++pocet_prvkov;
}
T read(int pozicia) const{
if ((pozicia < DOLNY_INDEX) || (pozicia >=pocet_prvkov+DOLNY_INDEX)){
throw std::out_of_range("Mimo.");
return T();
}else{
return pole[pozicia-DOLNY_INDEX];
}
}
/* void write(int pozicia, const T& novy_prvok_){
int skutocna_pozicia = pozicia - DOLNY_INDEX;
if (skutocna_pozicia < 0){
throw std::out_of_range("Mimo");
return;
}
//Sme nad nulou.
if (skutocna_pozicia < alokovane){
//vsetky prvky medzi pocet_prvkov a alokovane su vytvorene konstruktorom T()
//takze
pole[skutocna_pozicia] = novy_prvok_;
return;
}
//Ak sme za alokovanym miestom:
T * pomocne_pole;
try{
pomocne_pole = new T[skutocna_pozicia+MINIM_ALOK]; //Pridame este nejaku rezervu za pole;
}catch(...){ //TODO: Aku vynimku vracia new?
cerr << "Malo pamate! Vynimka." << endl;
return;
}
alokovane = skutocna_pozicia+MINIM_ALOK;
for (int i = 0; i<pocet_prvkov; ++i){
pomocne_pole[i] = pole[i];
}
delete pole;
pole = pomocne_pole;
pole[skutocna_pozicia] = novy_prvok_;
}
*/
T& write (int pozicia){ //Takmer kopia kodu z write()
//TODO: Odstranit dva krat ten isty kod!
int skutocna_pozicia = pozicia - DOLNY_INDEX;
if (skutocna_pozicia < 0){
throw std::out_of_range("Mimo");
}
//Sme nad nulou.
if (skutocna_pozicia < alokovane){
//vsetky prvky medzi pocet_prvkov a alokovane su vytvorene konstruktorom T()
//takze
if(pocet_prvkov <= skutocna_pozicia){
pocet_prvkov = skutocna_pozicia + 1;
}
return pole[skutocna_pozicia];
}
//Ak sme za alokovanym miestom:
T * pomocne_pole;
try{
pomocne_pole = new T[skutocna_pozicia+MINIM_ALOK]; //Pridame este nejaku rezervu za pole;
}catch(...){ //TODO: Aku vynimku vracia new?
std::cerr << "Malo pamate! Vynimka." << std::endl;
}
alokovane = skutocna_pozicia+MINIM_ALOK;
for (int i = 0; i<pocet_prvkov; ++i){
pomocne_pole[i] = pole[i];
}
delete pole;
pole = pomocne_pole;
pocet_prvkov = skutocna_pozicia+1;
return pole[skutocna_pozicia];
}
void clear(){
delete pole;
pocet_prvkov = 0;
alokovane = MINIM_ALOK;
pole = new T[MINIM_ALOK];
}
/* class vrat_pri_at{
public:
vrat_pri_at(gpole< T, dolny_index> * pole_, int pozicia_):pole(pole_), pozicia(pozicia_){}
operator T() const{
return pole->read(pozicia);
}
const vrat_pri_at & operator=(T novy){
t->write(pozicia, novy);
return *this;
}
private:
gpole < T, dolny_index> *pole;
int pozicia;
};
T at(int pozicia_) const{
return read(pozicia_);
}
vrat_pri_at & at(int pozicia){
return vrat_pri_at(*this, pozicia_);
}
*/
// friend std::ostream & operator<<(std::ostream & s, gpole <T, dolny_index>);
// friend std::istream & operator>>(std::istream & s, gpole <T, dolny_index>);
};
template <typename T, int n> std::ostream & operator<<(std::ostream & s, const gpole <T, n> & pole){
for (int i = 0; i<pole.pocet_prvkov; i++){
s << pole.pole[i] << " ";
}
return s;
}
template <typename T, int n> std::istream & operator>>(std::istream & s, gpole <T, n> & pole){
pole.clear();
T pomocny_prvok;
s >> pomocny_prvok;
do{
pole.push_back(pomocny_prvok);
s >> pomocny_prvok;
}while (!s.fail());
return s;
}
int main(){
gpole <testovacia_trieda, -2> a;
if(a.empty()){
std::cout << "Prazdny." << std::endl;
}
a.begin();
//a.at(1) = 2;
//std::cout << a.read(5);
a.write(6) = 3;
a.write(-1) = 4;
a.write(-2) = 6;
a.write(0) = 12;
std::cout << a;
// std::cout << a.read(6);
std::cin >> a;
std::sort(a.begin(), a.end());
std::cout << a;
return 0;
}