10. Iterátorok

Czirkos Zoltán · 2019.02.27.

Verem, automatikusan átméreteződő tömb, pakolt tömb indexelése

1. Verem és iterátor

#include <iostream>

template <typename T>
class Stack {
    private:
        struct StackElem {
            T data;
            StackElem *next;
        };

        StackElem *top;

    public:
        Stack() : top(NULL) {}
        ~Stack() {
            while (!empty())
                pop();
        }
        Stack(Stack const &); /* hf */
        Stack & operator=(Stack const &); /* hf */

        void push(T const & data) {
            StackElem *new_elem = new StackElem;
            new_elem->data = data;
            new_elem->next = top;
            top = new_elem;
        }

        T pop() {
            T top_data = top->data;
            StackElem *old_top = top;
            top = top->next;
            delete old_top;
            return top_data;
        }

        bool empty() const {
            return top == NULL;
        }

        class Iterator {
            private:
                StackElem *curr;

            public:
                Iterator() {}
                Iterator(StackElem *curr) : curr(curr) {}

                Iterator & operator++ () {
                    curr = curr->next;
                    return *this;
                }
                Iterator operator++ (int) {
                    Iterator old_value = *this;
                    curr = curr->next;
                    return old_value;       // posztinkremens!
                }
                T& operator* () {
                    return curr->data;
                }
                bool operator== (Iterator const & that) {
                    return this->curr == that.curr;
                }
                bool operator!= (Iterator const & that) {
                    return this->curr != that.curr;
                }
        };

        Iterator begin() {
            return Iterator(top);
        }
        Iterator end() {
            return Iterator(NULL);
        }
};

int main() {
    Stack<char> s;
    char c;
    while (std::cin >> c)
        s.push(c);

    std::cout << "Visszafelé a beírt szöveg, ahogy a veremben vannak, iterátorral:";
    for (Stack<char>::Iterator it = s.begin(); it != s.end(); ++it)
        std::cout << *it;
    std::cout << std::endl;

    std::cout << "Visszafelé a beírt szöveg, pop() függvénnyel:";
    while (!s.empty())
        std::cout << s.pop();
    std::cout << std::endl;
}

2. IMSc: Automatikusan átméreteződő tömb az std::vector-ból

Templatelt tömb, ami azt std::vectort használja a gyors/rövid implementációhoz. Automatikusan átméreteződik, ha túlindexelik. A privát "öröklés" (AMI OOP-ÉRTELEMBEN VÉVE NEM ÖRÖKLÉS, MERT NEM FEJEZ KI "X EGY FAJTA Y" KAPCSOLATOT!!!) elrejti az ősosztály függvényeit, és magát az öröklés tényét. Így nem lesz automatikus Tomb<T>->std::vector<T> konverzió, nem lehet majd tévesen meghívni a "régi" operator[]-t, amelyik nem méretez át.

#include <iostream>
#include <vector>

template <typename T>
class Tomb: private std::vector<T> {
private:
    /* Nem kell további adattag */ 

public:
    T& operator[](size_t i) {
        if (i>=size())
            this->resize(i+1);
        return std::vector<T>::operator[](i);
    }

    /* a privát "öröklés" (nem öröklés!) miatt ezek a függvények
     * és típusok nem látszanak kívülről. hogy újra láthatóvá
     * tegyük őket, arra a using kulcsszó való. */
    using std::vector<T>::size;
    using std::vector<T>::empty;
    using std::vector<T>::iterator;
    using std::vector<T>::begin;
    using std::vector<T>::end;
};

3. IMSc: Pakolt tömb indexelése

#include <iostream>
#include <list>
#include <vector>
#include <algorithm>

template <typename T>
class myvector {
    T* data;

    myvector(size_t s) {
        data = new T[s];
    }

    T & operator[] (size_t idx) {
        return data[idx];
    }

    /* copy ctor, etc, ami kell */
};

template <>
class myvector<bool> {
    unsigned char * data;

  public:
    myvector(size_t s) {
        data = new unsigned char [(s+7) / 8] ();
    }

    bool get_bit(size_t idx) const {
        return (data[idx/8] >> (idx % 8)) & 1;
    }

    void set_bit(size_t idx, bool b) {
        if (b == true) {
            data[idx/8] |= 1 << (idx % 8);
        } else {
            data[idx/8] &= ~(1 << (idx % 8));
        }
    }

    // Indexeléskor ilyen objektum keletkezik.
    // Ennek az értékadó és konverziós operátora van
    // úgy overloadolva, hogy aztán bitként viselkedik.
    class Proxy {
        private:
            myvector & v;
            size_t idx;
        public:
            Proxy(myvector & v, size_t idx) : v(v), idx(idx) {}
            operator bool () const {
                return v.get_bit(idx);
            }
            Proxy const & operator= (bool b) const {
                v.set_bit(idx, b);
                return *this;
            }
    };

    Proxy operator[] (size_t idx) {
        return Proxy(*this, idx);
    }

    ~myvector() {
        delete[] data;
    }
    // + copy ctor, etc
};



int main() {
    myvector<bool> v(200);
    v[175] = true;      // v.operator[](175) .operator=(true)
    std::cout << v[12]; // v.operator[](12)  .operator bool()

    // miért nem megy? hogy kell javítani?
    // v[175] = v[12];
}